Sei sulla pagina 1di 112

GIET (A)

REGULATION – GR17

ADVANCED DATA STRUCTURE LABORATORY

OUTCOMES:
After Completion of this course, a successful student will be able to:
Describe and implement a variety of advanced data structures (hash tables, balanced search trees,
graphs).
Demonstrate an understanding of external memory and external search and sorting algorithms.
Analyze the space and time complexity of the algorithms studied the course.
Design algorithms related to file structures.

SOFTWARE REQUIREMENTS:
C, C++

Course Objective(s):

To analyze algorithms and to determine algorithm correctness and time efficiency class.
Master a variety of advanced abstract data type (ADT) and data structures and their
implementations.
Master different algorithm design techniques
Ability to apply and implement learned algorithm design techniques and data structures to solve
problems.

1
List of Experiments

1. To implement functions of Dictionary using Hashing (division method, Multiplication method,


Universal hashing)
2. To perform various operations i.e, insertions and deletions on AVL trees
3. To perform various operations i.e., insertions and deletions on 2-3 trees.
4. To implement operations on binary heap.
5. To implement operations on graphs
a) vertex insertion
b) Vertex deletion
c) finding vertex
d) Edge addition and deletion
6. To implement Depth First Search for a graph non recursively.
7. To implement Breadth First Search for a graph non recursively.
8. To implement Prim’s algorithm to generate a min-cost spanning tree.
9. To implement Krushkal’s algorithm to generate a min-cost spanning tree.
10. To implement Dijkstra’s algorithm to find shortest path in the graph.
11. To implement pattern matching using Boyer-Moore algorithm.
12. To implement Knuth-Morris-Pratt algorithm for pattern matching.

Additional Experiments

13. Program to implement priority queue.


14. Search Operation in SPLAY TREE.
15. Implementation of Red-Black Tree Insertion.
16. C program for Fibonacci Search.
17. Largest subarray with equal number of 0s and 1s.
18. Union-find algorithm to detect cycle in a graph.
19. Merge Two Balanced Binary Search Trees.
20. How to handle duplicates in Binary Search Tree?
21. Count smaller elements on right side.
22. Find shortest unique prefix for every word in a given list.
23. Implement a Phone Directory.

2
ADVANCED DATA STRUCTURE LABORATORY
INDEX SHEET

S.no Experiment Name Page no


1 To implement functions of Dictionary using Hashing (division method,
Multiplication method, Universal hashing) 03-07
2 To perform various operations i.e, insertions and deletions on AVL trees 07-17
3 To perform various operations i.e., insertions and deletions on 2-3 trees. 17-25
4 To implement operations on binary heap. 26-33
5 To implement operations on graphs 33-40
a)vertex insertion
b)Vertex deletion
c)finding vertex
d)Edge addition and deletion
6 To implement Depth First Search for a graph non recursively 40-44
7 To implement Breadth First Search for a graph non recursively. 44-47
8 To implement Prim’s algorithm to generate a min-cost spanning tree. 48-51
9 To implement Krushkal’s algorithm to generate a min-cost spanning 52-57
tree.
10 To implement Dijkstra’s algorithm to find shortest path in the graph. 57-61
11 To implement pattern matching using Boyer-Moore algorithm. 61-66
12 To implement Knuth-Morris-Pratt algorithm for pattern matching. 66-69
13 Program to implement priority queue 69-73
14 Search Operation in SPLAY TREE 73-77
15 Implementation of Red-Black Tree Insertion 78-85
16 C program for Fibonacci Search 85-87
17 Largest subarray with equal number of 0s and 1s. 87-87
18 Union-find algorithm to detect cycle in a graph 89-92
19 Merge Two Balanced Binary Search Trees. 92-97
20 How to handle duplicates in Binary Search Tree? 97-102
21 Count smaller elements on right side 102-104
22 Find shortest unique prefix for every word in a given list 104-107
23 Implement a Phone Directory 107-112

3
EXPERIMENT-1: program to implement functions of Dictionary using hashing.
DESCRIPTION:
Suppose we want to design a system for storing employee records keyed using phone numbers. And we
want following queries to be performed efficiently:
1. Insert a phone number and corresponding information.
2. Search a phone number and fetch the information.
3. Delete a phone number and related information.
We can think of using the following data structures to maintain information about different phone
numbers.
1. Array of phone numbers and records.
2. Linked List of phone numbers and records.
3. Balanced binary search tree with phone numbers as keys.
4. Direct Access Table.
For arrays and linked lists, we need to search in a linear fashion, which can be costly in practice. If we
use arrays and keep the data sorted, then a phone number can be searched in O(Logn) time using Binary
Search, but insert and delete operations become costly as we have to maintain sorted order.
Hashing is an improvement over Direct Access Table. The idea is to use hash function that converts a
given phone number or any other key to a smaller number and uses the small number as index in a table
called hash table.
Hash Function: A function that converts a given big phone number to a small practical integer value.
The mapped integer value is used as an index in hash table. In simple terms, a hash function maps a big
number or string to a small integer that can be used as index in hash table.
A good hash function should have following properties
1)Efficiently computable.
2) Should uniformly distribute the keys (Each table position equally likely for each key)
For example for phone numbers a bad hash function is to take first three digits. A better function is
consider last three digits. Please note that this may not be the best hash function. There may be better
ways.
Hash Table: An array that stores pointers to records corresponding to a given phone number. An entry
in hash table is NIL if no existing phone number has hash function value equal to the index for the entry.

PROGRAM:

#include<stdio.h>
#include<string.h>
#include<process.h>
struct hashtuple
{
int key;
char data;
}table[10];
int divisor=10,size=10;
int search(int key)
{
int i=key%divisor;
4
int j=i;
do
{
if(table[j].data==0||table[j].key)
return j;
j=(j+1)%divisor;
}while(j!=i);
return j;
}
int find(int key)
{
int b=search(key);
if(table[b].data==0||table[b].key!=key)
return 0;
else
return table[b].data;
}
void insert(struct hashtuple ht)
{
int b=search(ht.key);
if(table[b].data==0)
{
table[b]=ht;
size++;
}
else
{
if(table[b].key==ht.key)
table[b].data=ht.data;
else
printf("hash table is FULL");
}}
void display()
{
int i;
for(i=0;i<divisor;i++)
{
if(table[i].data==0)
printf("NULL\n");
else{
printf("%d",table[i].key);
printf("%d\n",table[i].data);
}
}
}
int Size()
5
{
return size;
}
void main()
{
struct hashtuple table[11],t;
int i,ch,k;
clrscr();
for(i=0;i<divisor;i++)
table[i].data=0;
do
{
printf("\n1.insertion\n2.find\n3.size\n4.display\n5.exit\n");
scanf("%d",&ch);
switch(ch)
{
case 1:printf("Enter the key value:");
scanf("%d",&t.key);
printf("Enter the data value:");
scanf("%d",&t.data);
insert(t);
break;
case 2:printf("Enter search key:");
scanf("%d",&k);
printf("The associated with %d is %d",k,find(k));
break;
case 3:printf("the size of hash table %d",Size());
break;
case 4:printf("The hash table is \n");
display();
break;
case 5:exit(0);
}
}while(1);
}

OUTPUT:

1.insertion
2.find
3.size
4.display
5.exit
1
Enter the key value:23
Enter the data value:6

6
1.insertion
2.find
3.size
4.display
5.exit
1
Enter the key value:45
Enter the data value:8

1.insertion
2.find
3.size
4.display
5.exit
1
Enter the key value:7
Enter the data value:3

1.insertion
2.find
3.size
4.display
5.exit
4
The hash table is
NULL
NULL
NULL
236
NULL
458
NULL
73
NULL
NULL

1.insertion
2.find
3.size
4.display
5.exit
1
Enter the key value:13
Enter the data value:45
hash table is FULL
1.insertion
2.find
3.size
4.display

7
5.exit
3
the size of hash table 13
1.insertion
2.find
3.size
4.display
5.exit
5

EXPERIMENT-2: program to implement operations i.e, insertions and deletions on


AVL trees

DESCRIPTION:
AVL tree is a self-balancing Binary Search Tree (BST) where the difference between heights of left and right
subtrees cannot be more than one for all nodes.
An Example Tree that is an AVL Tree

Steps to follow for insertion


Let the newly inserted node be w
1) Perform standard BST insert for w.
2) Starting from w, travel up and find the first unbalanced node. Let z be the first unbalanced node, y be
the child of z that comes on the path from w to z and x be the grandchild of z that comes on the path
from w to z.
3) Re-balance the tree by performing appropriate rotations on the subtree rooted with z. There can be 4
possible cases that needs to be handled as x, y and z can be arranged in 4 ways. Following are the
possible 4 arrangements:
a) y is left child of z and x is left child of y (Left Left Case)
b) y is left child of z and x is right child of y (Left Right Case)
c) y is right child of z and x is right child of y (Right Right Case)
d) y is right child of z and x is left child of y (Right Left Case)
Following are the operations to be performed in above mentioned 4 cases. In all of the cases, we only
need to re-balance the subtree rooted with z and the complete tree becomes balanced as the height of
subtree (After appropriate rotations) rooted with z becomes same as it was before insertion.
(See this video lecture for proof)
a) Left Left Case

8
T1, T2, T3 and T4 are subtrees.
z y
/\ / \
y T4 Right Rotate (z) x z
/\ - - - - - - - - -> / \ / \
x T3 T1 T2 T3 T4
/\
T1 T2

b) Left Right Case


z z x
/\ / \ / \
y T4 Left Rotate (y) x T4 Right Rotate(z) y z
/\ - - - - - - - - -> / \ - - - - - - - -> / \ / \
T1 x y T3 T1 T2 T3 T4
/\ /\
T2 T3 T1 T2

c) Right Right Case


z y
/ \ / \
T1 y Left Rotate(z) z x
/ \ - - - - - - - -> /\ /\
T2 x T1 T2 T3 T4
/\
T3 T4

d) Right Left Case


z z x
/\ /\ / \
T1 y Right Rotate (y) T1 x Left Rotate(z) z y
/ \ - - - - - - - - -> / \ - - - - - - - -> / \ / \
x T4 T2 y T1 T2 T3 T4
/\ / \
T2 T3 T3 T4

9
Insertion Examples:

10
PROGRA
M:

#include<stdio.h>
typedef struct node
{
int data;
struct node *left,*right;
int ht;
11
}node;
node *insert(node *,int);
node *Delete(node *,int);
void inorder(node *);
int height( node *);
node *rotateright(node *);
node *rotateleft(node *);
node *RR(node *);
node *LL(node *);
node *LR(node *);
node *RL(node *);
int BF(node *);
int main()
{
node *root=NULL;
int x,n,i,op;

do
{
printf("\n1)Create:");
printf("\n2)Insert:");
printf("\n3)Delete:");
printf("\n4)Print:");
printf("\n5)Quit:");
printf("\n\nEnter Your Choice:");
scanf("%d",&op);
switch(op)
{
case 1: printf("\nEnter no. of elements:");
scanf("%d",&n);
printf("\nEnter tree data:");
root=NULL;
for(i=0;i<n;i++)
{
scanf("%d",&x);
root=insert(root,x);
}
break;
case 2: printf("\nEnter a data:");
scanf("%d",&x);
root=insert(root,x);
break;
case 3: printf("\nEnter a data:");
scanf("%d",&x);
root=Delete(root,x);
break;
12
case 4:
printf("\n\nsequence:\n");
inorder(root);
printf("\n");
break;
}
}while(op!=5);
return 0;
}
node * insert(node *T,int x)
{
if(T==NULL)
{
T=(node*)malloc(sizeof(node));
T->data=x;
T->left=NULL;
T->right=NULL;
}
else
if(x > T->data)
{
T->right=insert(T->right,x);
if(BF(T)==-2)
if(x>T->right->data)
T=RR(T);
else
T=RL(T);
}
else
if(x<T->data)
{
T->left=insert(T->left,x);
if(BF(T)==2)
if(x < T->left->data)
T=LL(T);
else
T=LR(T);
}
T->ht=height(T);
return(T);
}
node * Delete(node *T,int x)
{
node *p;
if(T==NULL)
{
13
return NULL;
}
else
if(x > T->data)
{
T->right=Delete(T->right,x);
if(BF(T)==2)
if(BF(T->left)>=0)
T=LL(T);
else
T=LR(T);
}
else
if(x<T->data)
{
T->left=Delete(T->left,x);
if(BF(T)==-2)
if(BF(T->right)<=0)
T=RR(T);
else
T=RL(T);
}
else
{

if(T->right!=NULL)
{
p=T->right;
while(p->left!= NULL)
p=p->left;
T->data=p->data;
T->right=Delete(T->right,p->data);
if(BF(T)==2)
if(BF(T->left)>=0)
T=LL(T);
else
T=LR(T);\
}
else
return(T->left);
}
T->ht=height(T);
return(T);
}
int height(node *T)
{
14
int lh,rh;
if(T==NULL)
return(0);

if(T->left==NULL)
lh=0;
else
lh=1+T->left->ht;
if(T->right==NULL)
rh=0;
else
rh=1+T->right->ht;
if(lh>rh)
return(lh);
return(rh);
}
node * rotateright(node *x)
{
node *y;
y=x->left;
x->left=y->right;
y->right=x;
x->ht=height(x);
y->ht=height(y);
return(y);
}
node * rotateleft(node *x)
{
node *y;
y=x->right;
x->right=y->left;
y->left=x;
x->ht=height(x);
y->ht=height(y);
return(y);
}
node * RR(node *T)
{
T=rotateleft(T);
return(T);
}
node * LL(node *T)
{
T=rotateright(T);
return(T);
}
15
node * LR(node *T)
{
T->left=rotateleft(T->left);
T=rotateright(T);
return(T);
}
node * RL(node *T)
{
T->right=rotateright(T->right);
T=rotateleft(T);
return(T);
}
int BF(node *T)
{
int lh,rh;
if(T==NULL)
return(0);
if(T->left==NULL)
lh=0;
else
lh=1+T->left->ht;
if(T->right==NULL)
rh=0;
else
rh=1+T->right->ht;
return(lh-rh);
}
void inorder(node *T)
{
if(T!=NULL)
{
printf("%d ->",T->data);
inorder(T->left);
inorder(T->right);
}
}
OUTPUT:

1)Create:
2)Insert:
3)Delete:
4)Print:
5)Quit:
Enter Your Choice:1
Enter no. of elements:5
Enter tree data:2 5 3 4 6
16
1)Create:
2)Insert:
3)Delete:
4)Print:
5)Quit:
Enter Your Choice:2
Enter a data:8
1)Create:
2)Insert:
3)Delete:
4)Print:
5)Quit:
Enter Your Choice:4
sequence:
5 ->3 ->2 ->4 ->6 ->8 ->
1)Create:
2)Insert:
3)Delete:
4)Print:
5)Quit:

Enter Your Choice:3


Enter a data:8
1)Create:
2)Insert:
3)Delete:
4)Print:
5)Quit:
Enter Your Choice:4
sequence:
5 ->3 ->2 ->4 ->6 ->
1)Create:
2)Insert:
3)Delete:
4)Print:
5)Quit:
Enter Your Choice:5

EXPERIMENT-3: To Perform a Program of insertion and deletion in 2-3 tree.


DESCRIPTION:
2-3 Trees
 leaf nodes
1. contain data items
17
2. all leaves on same level
 nonleaf node
1. has 2 or 3 children
2. two search values
i) largest item in left subtree
ii) largest item in middle subtree
smallest 2-3 tree { only one node (leaf node)

PROGRAM:
#include<stdio.h>
#include <conio.h>
#define M 5
struct node{
int n; /* n < M No. of keys in node will always less than order of B
tree */
int keys[M-1]; /*array of keys*/
struct node *p[M]; /* (n+1 pointers will be in use) */
}*root=NULL;
enum KeyStatus { Duplicate,SearchFailure,Success,InsertIt,LessKeys };
void insert(int key);
void display(struct node *root,int);
void DelNode(int x);
void search(int x);
enum KeyStatus ins(struct node *r, int x, int* y, struct node ** u);
int searchPos(int x,int *key_arr, int n);
enum KeyStatus del(struct node *r, int x);
int main()
{
int key;
int choice;
printf("Creation of B tree for node %d\n",M);
while(1)
{
printf("1.Insert\n");
printf("2.Delete\n");
printf("3.Search\n");
printf("4.Display\n");
printf("5.Quit\n");
printf("Enter your choice : ");
scanf("%d",&choice);
switch(choice)
{
case 1:
printf("Enter the key : ");
scanf("%d",&key);
insert(key);
18
break;
case 2:
printf("Enter the key : ");
scanf("%d",&key);
DelNode(key);
break;
case 3:
printf("Enter the key : ");
scanf("%d",&key);
search(key);
break;
case 4:
printf("Btree is :\n");
display(root,0);
break;
case 5:
exit(1);
default:
printf("Wrong choice\n");
break;
}/*End of switch*/
}/*End of while*/
return 0;
}/*End of main()*/
void insert(int key)
{
struct node *newnode;
int upKey;
enum KeyStatus value;
value = ins(root, key, &upKey, &newnode);
if (value == Duplicate)
printf("Key already available\n");
if (value == InsertIt)
{
struct node * uproot = root;
root=(struct node *)malloc(sizeof(struct node));
root->n = 1;
root->keys[0] = upKey;
root->p[0] = uproot;
root->p[1] = newnode;
}/*End of if */
}/*End of insert()*/
enum KeyStatus ins(struct node *ptr, int key, int *upKey,struct node **newnode)
{
struct node *newPtr, *lastPtr;
int pos, i, n,splitPos;
19
int newKey, lastKey;
enum KeyStatus value;
if (ptr == NULL)
{
*newnode = NULL;
*upKey = key;
return InsertIt;
}
n = ptr->n;
pos = searchPos(key, ptr->keys, n);
if (pos < n && key == ptr->keys[pos])
return Duplicate;
value = ins(ptr->p[pos], key, &newKey, &newPtr);
if (value != InsertIt)
return value;
/*If keys in node is less than M-1 where M is order of B tree*/
if (n < M - 1)
{
pos = searchPos(newKey, ptr->keys, n);
/*Shifting the key and pointer right for inserting the new key*/
for (i=n; i>pos; i--)
{
ptr->keys[i] = ptr->keys[i-1];
ptr->p[i+1] = ptr->p[i];
}
/*Key is inserted at exact location*/
ptr->keys[pos] = newKey;
ptr->p[pos+1] = newPtr;
++ptr->n; /*incrementing the number of keys in node*/
return Success;
}/*End of if */
/*If keys in nodes are maximum and position of node to be inserted is
last*/
if (pos == M - 1)
{
lastKey = newKey;
lastPtr = newPtr;
}
else /*If keys in node are maximum and position of node to be inserted
is not last*/
{
lastKey = ptr->keys[M-2];
lastPtr = ptr->p[M-1];
for (i=M-2; i>pos; i--)
{
ptr->keys[i] = ptr->keys[i-1];
20
ptr->p[i+1] = ptr->p[i];
}
ptr->keys[pos] = newKey;
ptr->p[pos+1] = newPtr;
}
splitPos = (M - 1)/2;
(*upKey) = ptr->keys[splitPos];
(*newnode)=(struct node *)malloc(sizeof(struct node));/*Right node after split*/
ptr->n = splitPos; /*No. of keys for left splitted node*/
(*newnode)->n = M-1-splitPos;/*No. of keys for right splitted node*/
for (i=0; i < (*newnode)->n; i++)
{
(*newnode)->p[i] = ptr->p[i + splitPos + 1];
if(i < (*newnode)->n - 1)
(*newnode)->keys[i] = ptr->keys[i + splitPos + 1];
else
(*newnode)->keys[i] = lastKey;
}
(*newnode)->p[(*newnode)->n] = lastPtr;
return InsertIt;
}/*End of ins()*/
void display(struct node *ptr, int blanks)
{
if (ptr)
{
int i;
for(i=1;i<=blanks;i++)
printf(" ");
for (i=0; i < ptr->n; i++)
printf("%d ",ptr->keys[i]);
printf("\n");
for (i=0; i <= ptr->n; i++)
display(ptr->p[i], blanks+10);
}/*End of if*/
}/*End of display()*/
void search(int key)
{
int pos, i, n;
struct node *ptr = root;
printf("Search path:\n");
while (ptr)
{
n = ptr->n;
for (i=0; i < ptr->n; i++)
printf(" %d",ptr->keys[i]);
printf("\n");
21
pos = searchPos(key, ptr->keys, n);
if (pos < n && key == ptr->keys[pos])
{
printf("Key %d found in position %d of last dispalyednode\n",key,i);
return;
}
ptr = ptr->p[pos];
}
printf("Key %d is not available\n",key);
}/*End of search()*/
int searchPos(int key, int *key_arr, int n)
{
int pos=0;
while (pos < n && key > key_arr[pos])
pos++;
return pos;
}/*End of searchPos()*/
void DelNode(int key)
{
struct node *uproot;
enum KeyStatus value;
value = del(root,key);
switch (value)
{
case SearchFailure:
printf("Key %d is not available\n",key);
break;
case LessKeys:
uproot = root;
root = root->p[0];
free(uproot);
break;
}/*End of switch*/
}/*End of delnode()*/
enum KeyStatus del(struct node *ptr, int key)
{
int pos, i, pivot, n ,min;
int *key_arr;
enum KeyStatus value;
struct node **p,*lptr,*rptr;
if (ptr == NULL)
return SearchFailure;
/*Assigns values of node*/
n=ptr->n;
key_arr = ptr->keys;
p = ptr->p;
22
min = (M - 1)/2;/*Minimum number of keys*/
pos = searchPos(key, key_arr, n);
if (p[0] == NULL)
{
if (pos == n || key < key_arr[pos])
return SearchFailure;
/*Shift keys and pointers left*/
for (i=pos+1; i < n; i++)
{
key_arr[i-1] = key_arr[i];
p[i] = p[i+1];
}
return --ptr->n >= (ptr==root ? 1 : min) ? Success : LessKeys;
}/*End of if */
if (pos < n && key == key_arr[pos])
{
struct node *qp = p[pos], *qp1;
int nkey;
while(1)
{
nkey = qp->n;
qp1 = qp->p[nkey];
if (qp1 == NULL)
break;
qp = qp1;
}/*End of while*/
key_arr[pos] = qp->keys[nkey-1];
qp->keys[nkey - 1] = key;
}/*End of if */
value = del(p[pos], key);
if (value != LessKeys)
return value;
if (pos > 0 && p[pos-1]->n > min)
{
pivot = pos - 1; /*pivot for left and right node*/
lptr = p[pivot];
rptr = p[pos];
/*Assigns values for right node*/
rptr->p[rptr->n + 1] = rptr->p[rptr->n];
for (i=rptr->n; i>0; i--)
{
rptr->keys[i] = rptr->keys[i-1];
rptr->p[i] = rptr->p[i-1];
}
rptr->n++;
rptr->keys[0] = key_arr[pivot];
23
rptr->p[0] = lptr->p[lptr->n];
key_arr[pivot] = lptr->keys[--lptr->n];
return Success;
}/*End of if */
if (pos > min)
{
pivot = pos; /*pivot for left and right node*/
lptr = p[pivot];
rptr = p[pivot+1];
/*Assigns values for left node*/
lptr->keys[lptr->n] = key_arr[pivot];
lptr->p[lptr->n + 1] = rptr->p[0];
key_arr[pivot] = rptr->keys[0];
lptr->n++;
rptr->n--;
for (i=0; i < rptr->n; i++)
{
rptr->keys[i] = rptr->keys[i+1];
rptr->p[i] = rptr->p[i+1];
}/*End of for*/
rptr->p[rptr->n] = rptr->p[rptr->n + 1];
return Success;
}/*End of if */
if(pos == n)
pivot = pos-1;
else
pivot = pos;
lptr = p[pivot];
rptr = p[pivot+1];
/*merge right node with left node*/
lptr->keys[lptr->n] = key_arr[pivot];
lptr->p[lptr->n + 1] = rptr->p[0];
for (i=0; i < rptr->n; i++)
{
lptr->keys[lptr->n + 1 + i] = rptr->keys[i];
lptr->p[lptr->n + 2 + i] = rptr->p[i+1];
}
lptr->n = lptr->n + rptr->n +1;
free(rptr); /*Remove right node*/
for (i=pos+1; i < n; i++)
{
key_arr[i-1] = key_arr[i];
p[i] = p[i+1];
}
return --ptr->n >= (ptr == root ? 1 : min) ? Success : LessKeys;
}
24
OUTPUT:
Creation of B tree for node 5
1.Insert
2.Delete
3.Search
4.Display
5.Quit

Enter your choice : 1


Enter the key : 10
1.Insert
2.Delete
3.Search
4.Display
5.Quit

Enter your choice : 1


Enter the key : 20
1.Insert
2.Delete
3.Search
4.Display
5.Quit

Enter your choice : 4


Btree is :
10 20
1.Insert
2.Delete
3.Search
4.Display
5.Quit

Enter your choice : 2


Enter the key : 10
1.Insert
2.Delete
3.Search
4.Display
5.Quit
Enter your choice : 4
Btree is :
20
1.Insert
2.Delete
25
3.Search
4.Display
5.Quit
Enter your choice :5

EXPERIMENT-4: To implement operations on binary heap.


DESCRIPTION:
Binary Heap
A Binary Heap is a Binary Tree with following properties.
1) It’s a complete tree (All levels are completely filled except possibly the last level and the last level
has all keys as left as possible). This property of Binary Heap makes them suitable to be stored in an
array.
2) A Binary Heap is either Min Heap or Max Heap. In a Min Binary Heap, the key at root must be
minimum among all keys present in Binary Heap. The same property must be recursively true for all
nodes in Binary Tree. Max Binary Heap is similar to MinHeap.
Examples of Min Heap:
10 10
/ \ / \
20 100 15 30
/ / \ / \
30 40 50 100 40

A Binary Heap is a Complete Binary Tree. A binary heap is typically represented as an array.
 The root element will be at Arr[0].
 Below table shows indexes of other nodes for the ith node, i.e., Arr[i]:
Arr[(i-1)/2] Returns the parent node

Arr[(2*i)+1] Returns the left child node

Arr[(2*i)+2] Returns the right child node

26
The traversal method use to achieve Array representation is Level Order

PROGRAM:

#include <stdio.h>

int array[100], n;

main()

int choice, num;

n = 0;/*Represents number of nodes in the heap*/

while(1)

printf("1.Insert the element \n");

printf("2.Delete the element \n");

printf("3.Display all elements \n");

printf("4.Quit \n");

printf("Enter your choice : ");

scanf("%d", &choice);

switch(choice)

case 1:

printf("Enter the element to be inserted to the list : ");


27
scanf("%d", &num);

insert(num, n);

n = n + 1;

break;

case 2:

printf("Enter the elements to be deleted from the list: ");

scanf("%d", &num);

delete(num);

break;

case 3:

display();

break;

case 4:

exit(0);

default:

printf("Invalid choice \n");

}/*End of switch */

}/*End of while */

}/*End of main()*/

display()

int i;
28
if (n == 0)

printf("Heap is empty \n");

return;

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

printf("%d ", array[i]);

printf("\n");

}/*End of display()*/

insert(int num, int location)

int parentnode;

while (location > 0)

parentnode =(location - 1)/2;

if (num <= array[parentnode])

array[location] = num;

return;

array[location] = array[parentnode];

location = parentnode;

}/*End of while*/
29
array[0] = num; /*assign number to the root node */
}/*End of insert()*/

delete(int num)

int left, right, i, temp, parentnode;

for (i = 0; i < num; i++) {

if (num == array[i])

break;

if (num != array[i])

printf("%d not found in heap list\n", num);

return;

array[i] = array[n - 1];

n = n - 1;

parentnode =(i - 1) / 2; /*find parentnode of node i */

if (array[i] > array[parentnode])

insert(array[i], i);

return;

left = 2 * i + 1; /*left child of i*/

30
right = 2 * i + 2; /* right child of i*/

while (right < n)

if (array[i] >= array[left] && array[i] >= array[right])

return;

if (array[right] <= array[left])

temp = array[i];

array[i] = array[left];

array[left] = temp;

i = left;

else

temp = array[i];

array[i] = array[right];

array[right] = temp;

i = right;

left = 2 * i + 1;

right = 2 * i + 2;

}/*End of while*/

if (left == n - 1 && array[i]) {

31
temp = array[i];

array[i] = array[left];

array[left] = temp;
}

OUTPUT:
1.Insert the element
2.Delete the element
3.Display all elements
4.Quit

Enter your choice : 1


Enter the element to be inserted to the list : 10
1.Insert the element
2.Delete the element
3.Display all elements
4.Quit

Enter your choice : 1


Enter the element to be inserted to the list : 20
1.Insert the element
2.Delete the element
3.Display all elements
4.Quit

Enter your choice : 1


Enter the element to be inserted to the list : 30
1.Insert the element
2.Delete the element
3.Display all elements
4.Quit

Enter your choice : 2


Enter the elements to be deleted from the list: 10
10 not found in heap list
1.Insert the element
2.Delete the element
3.Display all elements
4.Quit

Enter your choice : 2


32
Enter the elements to be deleted from the list: 20
1.Insert the element
2.Delete the element
3.Display all elements
4.Quit

Enter your choice : 1


Enter the element to be inserted to the list : 100
1.Insert the element
2.Delete the element
3.Display all elements
4.Quit

Enter your choice : 3


30 100
1.Insert the element
2.Delete the element
3.Display all elements
4.Quit
Enter your choice : 4

EXPERIMENT-5: Program to implement operations on graph.


i)insert vertex

ii)delete vertex

iii)add edge

iv)delete edge

v)find vertex

DESCRIPTION:

A Graph is a non-linear data structure consisting of nodes and edges. The nodes are sometimes also
referred to as vertices and the edges are lines or arcs that connect any two nodes in the graph. More
formally a Graph can be defined as,
A Graph consists of a finite set of vertices(or nodes) and set of Edges which connect a pair of nodes.

33
Graph is a data structure that consists of following two components:
1. A finite set of vertices also called as nodes.
2. A finite set of ordered pair of the form (u, v) called as edge. The pair is ordered because (u, v) is not
same as (v, u) in case of a directed graph(di-graph). The pair of the form (u, v) indicates that there is an
edge from vertex u to vertex v. The edges may contain weight/value/cost.
Graphs are used to represent many real-life applications: Graphs are used to represent networks. The
networks may include paths in a city or telephone network or circuit network. Graphs are also used in
social networks like linkedIn, Facebook. For example, in Facebook, each person is represented with a
vertex(or node). Each node is a structure and contains information like person id, name, gender and
locale. See this for more applications of graph.
Following is an example of an undirected graph with 5 vertices.

Following two are the most commonly used representations of a graph.


1. Adjacency Matrix
2. Adjacency List
There are other representations also like, Incidence Matrix and Incidence List. The choice of the graph
representation is situation specific. It totally depends on the type of operations to be performed and ease
of use.
Adjacency Matrix:
Adjacency Matrix is a 2D array of size V x V where V is the number of vertices in a graph. Let the 2D
array be adj[][], a slot adj[i][j] = 1 indicates that there is an edge from vertex i to vertex j. Adjacency
matrix for undirected graph is always symmetric. Adjacency Matrix is also used to represent weighted
graphs. If adj[i][j] = w, then there is an edge from vertex i to vertex j with weight w.

34
AdjacencyList:
An array of linked lists is used. Size of the array is equal to the number of vertices. Let the array be array
[]. An entry array[i] represents the linked list of vertices adjacent to the ith vertex. This representation
can also be used to represent a weighted graph. The weights of edges can be stored in nodes of linked
lists. Following is adjacency list representation of the above graph.

PROGRAM:
#include<stdio.h>
int a[10][10],n;
char v[10];
main()
{
int i,j,t,ch;
char f,x,s,d;
clrscr();
printf("Enter no of vertices");
scanf("%d",&n);
printf("Enter the vertices names");
for(i=0;i<n;i++)
scanf(" %c",&v[i]);
printf("Enter the adjacent vertices(0/1)");
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
scanf("%d",&a[i][j]);
35
}
}
do
{
printf("\n 1.Insert \n 2.Delete vertex \n 3.Find vertex \n 4.Add Edge \n 5.Delete Edge \n 6.Display\n
7.EXIT");
scanf("%d",&ch);
switch(ch)
{
case 1: printf("Enter the vertex");
scanf(" %c",&x);
insert(x);
break;
case 2: printf("Enter vertex to be deleted");
scanf(" %c",&x);
delete(x);
break;
case 3: printf("Enter the vertex to be found");
scanf(" %c",&f);
t=find(f);
if(t==-1)
printf("Not Found");
else
printf("Found");
break;
case 4: printf("enter the Edge");
scanf(" %c",&s);
scanf(" %c",&d);
addedge(s,d);
break;
case 5: printf("enter the Edge");
scanf(" %c",&s);
scanf(" %c",&d);
deleteedge(s,d);
break;
case 6: display();
break;
case 7:exit(0);
}
}while(1);
}
insert(char x)
{
int i;
v[n]=x;
n=n+1;
36
v[n+1]='\0';
for(i=0;i<n;i++)
a[i][n-1]=0;
for(i=0;i<n;i++)
a[n-1][i]=0;
}
delete(char x)
{
int i,j,r;
r=find(x);
if(r==-1)
printf("vertex not found");
else
{
for(i=r;i<n;i++)
v[i]=v[i+1];
v[i]='\0';
for(i=0;i<n;i++)
for(j=r;j<n;j++)
a[i][j]=a[i][j+1];
for(j=0;j<n;j++)
for(i=r;i<n;i++)
a[i][j]=a[i+1][j];
n--;
}
}
display()
{
int i,j;
printf("\nVertex Are:\n");
for(i=0;i<n;i++)
printf("%c ",v[i]);
printf("\nAdjancy matrix is:\n");
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
printf("%d ",a[i][j]);
printf("\n");
}
}
int find(char x)
{
int i;
for(i=0;i<n;i++)
{
if(v[i]==x)
37
return i;
}
return -1;
}
addedge(char s,char d)
{
int i,j;
i=find(s);
j=find(d);
if(i!=-1&&j!=-1)
{
a[i][j]=1;
a[j][i]=1;
}
else
printf("Vertices u entered are invalid");
}
deleteedge(char s, char d)
{
int i,j;
i=find(s);
j=find(d);
if(i!=-1&&j!=-1&&a[i][j]==1)
{
a[i][j]=0;
a[j][i]=0;
}
else
printf("Vertices u entered are invalid");
}
OUTPUT:
Enter no of vertices3
Enter the vertices names1 2 3
Enter the adjacent vertices(0/1)
001
100
001

1.Insert
2.Delete vertex
3.Find vertex
4.Add Edge
5.Delete Edge
6.Display
7.EXIT
1

38
Enter the vertex4

1.Insert
2.Delete vertex
3.Find vertex
4.Add Edge
5.Delete Edge
6.Display
7.EXIT
4
Enter the Edge:3 4

1.Insert
2.Delete vertex
3.Find vertex
4.Add Edge
5.Delete Edge
6.Display
7.EXIT
6

Vertex Are:
1234
Adjancy matrix is:
0010
1000
0011
0010

1.Insert
2.Delete vertex
3.Find vertex
4.Add Edge
5.Delete Edge
6.Display
7.EXIT
5
enter the Edge3 4

1.Insert
2.Delete vertex
3.Find vertex
4.Add Edge
5.Delete Edge
6.Display
7.EXIT
39
2
Enter vertex to be deleted4

1.Insert
2.Delete vertex
3.Find vertex
4.Add Edge
5.Delete Edge
6.Display
7.EXIT
3
Enter the vertex to be found2
Found
1.Insert
2.Delete vertex
3.Find vertex
4.Add Edge
5.Delete Edge
6.Display
7.EXIT
7

EXPERIMENT-6: Prgram to implement DFS for a graph non-recursively


DESCRIPTION:

Depth First Search or DFS for a Graph


Depth First Traversal (or Search) for a graph is similar to Depth First Traversal of a tree. The only catch
here is, unlike trees, graphs may contain cycles, so we may come to the same node again. To avoid
processing a node more than once, we use a boolean visited array.
For example, in the following graph, we start traversal from vertex 2. When we come to vertex 0, we
look for all adjacent vertices of it. 2 is also an adjacent vertex of 0. If we don’t mark visited vertices,
then 2 will be processed again and it will become a non-terminating process. A Depth First Traversal of
the following graph is 2, 0, 1, 3.
Illustration for an Undirected Graph :

40
41
42
PROGRAM:

#include<stdio.h>
#include<conio.h>
int a[10][10],st[10],visited[10],n,i,j,top=-1;
void dfs(int v)
{
while(1)
{
printf("%d ",v);
visited[v]=1;
for(i=n;i>=0;i--)
{
if(a[v][i]==1&&visited[i]==0)
push(i);
}
v=pop();
if(v==-1)
return;
}
}
push(int x)
{
if(top==9)
printf("Stack is Full");
else
st[++top]=x;
}
int pop()
{
if(top==-1)
return -1;
else
return(st[top--]);
}
void main()
{
int v;
clrscr();
printf("\nEnter the number of vertices:");
scanf("%d",&n);
for(i=0;i<n;i++)
visited[i]=0;
printf("\n Enter graph data in matrix form:\n");
for(i=0;i<n;i++)
for(j=0;j<n;j++)
43
scanf("%d",&a[i][j]);
printf("\n Enter the starting vertex:");
scanf("%d",&v);
dfs(v);
getch();
}

OUTPUT:
Enter the number of vertices:5
Enter graph data in matrix form:
01100
10010
10001
01000
00100
Enter the starting vertex:0
01324

EXPERIMENT-7: Program to implement BFS for a graph non-recursively


DESCRIPTION:

Breadth First Search or BFS for a Graph


Breadth First Traversal (or Search) for a graph is similar to Breadth First Traversal of a tree (See method
2 of this post). The only catch here is, unlike trees, graphs may contain cycles, so we may come to the
same node again. To avoid processing a node more than once, we use a boolean visited array. For
simplicity, it is assumed that all vertices are reachable from the starting vertex.
For example, in the following graph, we start traversal from vertex 2. When we come to vertex 0, we
look for all adjacent vertices of it. 2 is also an adjacent vertex of 0. If we don’t mark visited vertices,
then 2 will be processed again and it will become a non-terminating process. A Breadth First Traversal
of the following graph is 2, 0, 3, 1.

44
Illustration :

45
46
PROGRAM:
#include<stdio.h>
#include<conio.h>
int a[20][20],q[20],visited[20],n,i,j,f=-1,r=-1;
void bfs(int v)
{
printf("%d ",v);
visited[v]=1;
do
{
for(i=0;i<n;i++)
{
if(a[v][i]==1&&visited[i]==0)
{
q[++r]=i;
printf("%d ",i);
visited[i]=1;
}
}
if(f==r)
return;
else
v=q[f++];
}while(1);
}
void main()
{
int v;
clrscr();
printf("\n Enter the number of vertices:");
47
scanf("%d",&n);
for(i=0;i<n;i++)
{
q[i]=0;
visited[i]=0;
}
printf("\n Enter graph data in matrix form:\n");
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",&a[i][j]);
printf("\n Enter the starting vertex:");
scanf("%d",&v);
bfs(v);
getch();
}

OUTPUT:
Enter the number of vertices:5
Enter graph data in matrix form:
01100
10010
10001
01000
00100

Enter the starting vertex:0


01234

EXPERIMENT-8: Program to implement Prim’s algorithm to generate a min-cost


spanning tree
DESCRIPTION:

Algorithm
1) Create a set mstSet that keeps track of vertices already included in MST.
2) Assign a key value to all vertices in the input graph. Initialize all key values as INFINITE. Assign key
value as 0 for the first vertex so that it is picked first.
3) While mstSet doesn’t include all vertices
….a) Pick a vertex u which is not there in mstSet and has minimum key value.
….b) Include u to mstSet.
….c) Update key value of all adjacent vertices of u. To update the key values, iterate through all adjacent
vertices. For every adjacent vertex v, if weight of edge u-v is less than the previous key value of v,
update the key value as weight of u-v
The idea of using key values is to pick the minimum weight edge from cut. The key values are used only
for vertices which are not yet included in MST, the key value for these vertices indicate the minimum
weight edges connecting them to the set of vertices included in MST.
48
Let us understand with the following example:

The set mstSet is initially empty and keys assigned to vertices are {0, INF, INF, INF, INF, INF, INF,
INF} where INF indicates infinite. Now pick the vertex with minimum key value. The vertex 0 is
picked, include it in mstSet. So mstSet becomes {0}. After including to mstSet, update key values of
adjacent vertices. Adjacent vertices of 0 are 1 and 7. The key values of 1 and 7 are updated as 4 and 8.
Following subgraph shows vertices and their key values, only the vertices with finite key values are
shown. The vertices included in MST are shown in green color.

Pick the vertex with minimum key value and not already included in MST (not in mstSET). The vertex 1
is picked and added to mstSet. So mstSet now becomes {0, 1}. Update the key values of adjacent
vertices of 1. The key value of vertex 2 becomes 8.

Pick the vertex with minimum key value and not already included in MST (not in mstSET). We can
either pick vertex 7 or vertex 2, let vertex 7 is picked. So mstSet now becomes {0, 1, 7}. Update the key
values of adjacent vertices of 7. The key value of vertex 6 and 8 becomes finite (7 and 1 respectively).

Pick the vertex with minimum key value and not already included in MST (not in mstSET). Vertex 6 is
picked. So mstSet now becomes {0, 1, 7, 6}. Update the key values of adjacent vertices of 6. The key
value of vertex 5 and 8 are updated.

49
We repeat the above steps until mstSet includes all vertices of given graph. Finally, we get the following
graph.

PROGRAM:
#include<stdio.h>
#include<conio.h>
int n,cost[10][10];
void prim()
{
int i,j,k,l,x,nr[10],temp,min_cost=0,tree[10][3];
temp=cost[0][0];
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(temp>cost[i][j])
{
temp=cost[i][j];
k=i;
l=j;
}
}
}
tree[0][0]=k;
tree[0][1]=l;
tree[0][2]=temp;
min_cost=temp;
for(i=0;i<n;i++)
{
if(cost[i][k]<cost[i][l])
nr[i]=k;
else
nr[i]=l;
50
}
nr[k]=100;
nr[l]=100;
temp=99;
for(i=1;i<n;i++)
{
for(j=0;j<n;j++)
{
if(nr[j]!=100&&cost[j][nr[j]]<temp)
{
temp=cost[j][nr[j]];
x=j;
}}
tree[i][0]=x;
tree[i][1]=nr[x];
tree[i][2]=cost[x][nr[x]];
min_cost=min_cost+cost[x][nr[x]];
nr[x]=100;
for(j=0;j<n;j++)
{
if(nr[j]!=100 && cost[j][nr[j]]>cost[j][x])
nr[j]=x;
}
temp=99;
printf("\nthe min spanning tree is\n");
for(i=0;i<n-1;i++)
{
for(j=0;j<3;j++)
printf("%d",tree[i][j]);
printf("\n");
}
printf("\nMin cost:%d",min_cost);
} }
void main()
{
int i,j;
clrscr();
printf("\nEnter the no.of vertices:");
scanf("%d",&n);
printf("\nEnter the cost of edges in matrix form:");
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",&cost[i][j]);
printf("\nThe matrix is:\n");
for(i=0;i<n;i++)
{
51
for(j=0;j<n;j++)
printf("%d\t",cost[i][j]);
printf("\n");
}
prim();
getch();
}

OUTPUT:
Enter the no.of vertices:3
Enter the cost of edges in matrix form:
99 2 4
2 99 5
4 5 99
The matrix is:
99 2 4
2 99 5
4 5 99
the min spanning tree is
012
204
Min cost:6

EXPERIMENT-9: Program to implement Krushkal’s algorithm to generate a min-


cost spanning tree
DECRIPTION:

Below are the steps for finding MST using Kruskal’s algorithm
1. Sort all the edges in non-decreasing order of their weight.
2. Pick the smallest edge. Check if it forms a cycle with the spanning tree formed so far. If cycle is not
formed, include this edge. Else, discard it.
3. Repeat step#2 until there are (V-1) edges in the spanning tree.
The step#2 uses Union-Find algorithm to detect cycle. So we recommend to read following post as a
prerequisite.

The algorithm is a Greedy Algorithm. The Greedy Choice is to pick the smallest weight edge that does
not cause a cycle in the MST constructed so far. Let us understand it with an example: Consider the
below input graph.

52
The graph contains 9 vertices and 14 edges. So, the minimum spanning tree formed will be having (9 –
1) = 8 edges.

After sorting:
Weight Src Dest
1 7 6
2 8 2
2 6 5
4 0 1
4 2 5
6 8 6
7 2 3
7 7 8
8 0 7
8 1 2
9 3 4
10 5 4
11 1 7
14 3 5

Now pick all edges one by one from sorted list of edges
1. Pick edge 7-6: No cycle is formed, include it.

53
2. Pick edge 8-2: No cycle is formed, include it.

3. Pick edge 6-5: No cycle is formed, include it.

4. Pick edge 0-1: No cycle is formed, include it.

5. Pick edge 2-5: No cycle is formed, include it.

6. Pick edge 8-6: Since including this edge results in cycle, discard it.
7. Pick edge 2-3: No cycle is formed, include it.

8. Pick edge 7-8: Since including this edge results in cycle, discard it.

54
9. Pick edge 0-7: No cycle is formed, include it.

10. Pick edge 1-2: Since including this edge results in cycle, discard it.
11. Pick edge 3-4: No cycle is formed, include it.

Since the number of edges included equals (V – 1), the algorithm stops here.
PROGRAM:

#include<stdio.h>
#include<stdlib.h>
void printArray(int a[][100],int n);
void AdjacencyMatrix(int a[][100],int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<i;j++)
{
a[i][j]=a[j][i]=rand()%50;
if(a[i][j]>40) a[i][j]=a[j][i]=999; }
a[i][i]=999;
}
printArray(a,n);
}
void printArray(int a[][100],int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
printf("%d\t",a[i][j]);
}
printf("\n");
55
}
}
int root(int v,int p[])
{
while(p[v]!=v)
{
v=p[v];
}
return v;
}
void union_ij(int i,int j,int p[])
{
if(j>i)
p[j]=i;
else
p[i]=j;
}
void krushkal(int a[][100],int n)
{
int count,i,p[100],min,j,u,v,k,t[100][100],sum;
count=k=sum=0;
for(i=0;i<n;i++)
{
p[i]=i;
}
while(count<n)
{
min=999;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(a[i][j]<min)
{
min=a[i][j];
u=i;
v=j;
}
}
}
if(min!=999)
{
i=root(u,p);
j=root(v,p);
if(i!=j)
{
56
t[k][0]=u;
t[k][1]=v;
k++;
sum+=min;
union_ij(i,j,p);
}
a[u][v]=a[v][u]=999;
}
count+=1;
}
if(count!=n)
{
printf("spanning tree not exist\n");
}
if(count==n)
{
printf("Edges spanning tree is\n");
for(k=0;k<n-1;k++)
printf("%d->%d",t[k][0],t[k][1]);
printf("\ncost=%d\n",sum);
}}
int main()
{
int a[100][100],n;
clrscr();
printf("Enter the number of vertices:\n");
scanf("%d",&n);
AdjacencyMatrix(a,n);
krushkal(a,n);
return 0;
}

OUTPUT:
Enter the no.of vertices:3
Enter the cost of edges in matrix form:
99 2 4
2 99 5
4 5 99
The matrix is:
99 2 4
2 99 5
4 5 99

the min spanning tree is


012
204
57
Min cost:6

EXPERIMENT-10: Program to implement Dijikstra’s algorithm to find shortest


path in graph
DESCRIPTION:

1) Create a set sptSet (shortest path tree set) that keeps track of vertices included in shortest path tree,
i.e., whose minimum distance from source is calculated and finalized. Initially, this set is empty.
2) Assign a distance value to all vertices in the input graph. Initialize all distance values as INFINITE.
Assign distance value as 0 for the source vertex so that it is picked first.
3) While sptSet doesn’t include all vertices
a) Pick a vertex u which is not there in sptSet and has minimum distance value
b) Include u to sptSet
c) Update distance value of all adjacent vertices of u. To update the distance values, iterate through all
adjacent vertices. For every adjacent vertex v, if sum of distance value of u (from source) and weight of
edge u-v, is less than the distance value of v, then update the distance value of v.
Let us understand with the following example:

The set sptSet is initially empty and distances assigned to vertices are {0, INF, INF, INF, INF, INF, INF,
INF} where INF indicates infinite. Now pick the vertex with minimum distance value. The vertex 0 is
picked, include it in sptSet. So sptSet becomes {0}. After including 0 to sptSet, update distance values of
its adjacent vertices. Adjacent vertices of 0 are 1 and 7. The distance values of 1 and 7 are updated as 4
and 8. Following subgraph shows vertices and their distance values, only the vertices with finite distance
values are shown. The vertices included in SPT are shown in green colour.

Pick the vertex with minimum distance value and not already included in SPT (not in sptSET). The
vertex 1 is picked and added to sptSet. So sptSet now becomes {0, 1}. Update the distance values of
adjacent vertices of 1. The distance value of vertex 2 becomes 12.

58
Pick the vertex with minimum distance value and not already included in SPT (not in sptSET). Vertex 7
is picked. So sptSet now becomes {0, 1, 7}. Update the distance values of adjacent vertices of 7. The
distance value of vertex 6 and 8 becomes finite (15 and 9 respectively).

Pick the vertex with minimum distance value and not already included in SPT (not in sptSET). Vertex 6
is picked. So sptSet now becomes {0, 1, 7, 6}. Update the distance values of adjacent vertices of 6. The
distance value of vertex 5 and 8 are updated.

We repeat the above steps until sptSet doesn’t include all vertices of given graph. Finally, we get the
following Shortest Path Tree (SPT).

PROGRAM:

#include<stdio.h>
#include<conio.h>
#include<process.h>
#include<string.h>

59
#include<math.h>
# define IN 99
# define N 6
int dijkstra(int cost[][N],int source,int target);
int dijikstra(int cost[][N],int source,int target)
{
int dist[N],prev[N],selected[N]={0},i,m,min,start,d,j;
char path[N];
for(i=1;i<N;i++)
{
dist[i]=IN;
prev[i]=-1;
}
start=source;
selected[start]=1;
dist[start]=0;
while(selected[target]==0)
{
min=IN;
m=0;
for(i=1;i<N;i++)
{
d=dist[start]+cost[start][i];
if(d<dist[i]&&selected[i]==0)
{
dist[i]=d;
prev[i]=start;
}
if(min>dist[i]&&selected[i]==0)
{
min=dist[i];
m=i;
}
}
start=m;
selected[start]=1;
}
start=target;
j=0;
while(start!=-1)
{
path[j++]=start+65;
start=prev[start];
}
path[j]='\0';
strrev(path);
60
printf("%s",path);
return dist[target];
}
main()
{
int cost[N][N],i,j,w,ch,co;
int source,target,x,y;
clrscr();
printf("\tSHOPRTEST PATH ALGORITHM(DIJSKSTRA'S ALOGORITHM\n\n");
for(i=1;i<N;i++)
for(j=1;j<N;j++)
cost[i][j]=IN;
for(x=1;x<N;x++)
{
for(y=x+1;y<N;y++)
{
printf("Enter the weight of the path between node %d and %d:\t",x,y);
scanf("%d",&w);
cost[x][y]=cost[y][x]=w;
}
printf("\n");
}
printf("\nEnter the source:");
scanf("%d",&source);
printf("\nEnter the target:");
scanf("%d",&target);
co=dijikstra(cost,source,target);
printf("\nshortest path :%d",co);
getch();
}

OUTPUT:
SHOPRTEST PATH ALGORITHM(DIJSKSTRA'S ALOGORITHM
Enter the weight of the path between node 1 and 2: 1
Enter the weight of the path between node 1 and 3: 2
Enter the weight of the path between node 1 and 4: 3
Enter the weight of the path between node 1 and 5: 4

Enter the weight of the path between node 2 and 3: 5


Enter the weight of the path between node 2 and 4: 2
Enter the weight of the path between node 2 and 5: 5

Enter the weight of the path between node 3 and 4: 8


Enter the weight of the path between node 3 and 5: 4

Enter the weight of the path between node 4 and 5: 3


61
Enter the source:1
Enter the target:4
BE
shortest path :3

EXPERIMENT-11: Program to implement pattern matching using boyer-moore


algorithm
DESCRIPTION:

Pattern searching is an important problem in computer science. When we do search for a string in
notepad/word file or browser or database, pattern searching algorithms are used to show the search
results. A typical problem statement would be-
Given a text txt[0..n-1] and a pattern pat[0..m-1], write a function search(char pat[], char txt[]) that prints
all occurrences of pat[] in txt[]. You may assume that n > m.
Examples:

Input: txt[] = "THIS IS A TEST TEXT"


pat[] = "TEST"
Output: Pattern found at index 10

Input: txt[] = "AABAACAADAABAABA"


pat[] = "AABA"
Output: Pattern found at index 0
Pattern found at index 9
Pattern found at index 12

In this post, we will discuss Boyer Moore pattern searching algorithm. Like KMP and Finite
Automata algorithms, Boyer Moore algorithm also preprocesses the pattern.
Boyer Moore is a combination of following two approaches.

62
1) Bad Character Heuristic
2) Good Suffix Heuristic
Both of the above heuristics can also be used independently to search a pattern in a text. Let us first
understand how two independent approaches work together in the Boyer Moore algorithm. If we take a
look at the Naive algorithm, it slides the pattern over the text one by one. KMP algorithm does
preprocessing over the pattern so that the pattern can be shifted by more than one. The Boyer Moore
algorithm does preprocessing for the same reason. It preporcesses the pattern and creates different arrays
for both heuristics. At every step, it slides the pattern by max of the slides suggested by the two
heuristics. So it uses best of the two heuristics at every step.
Unlike the previous pattern searching algorithms, Boyer Moore algorithm starts matching from the last
character of the pattern.
In this post, we will discuss bad character heuristic, and discuss Good Suffix heuristic in the next post.
Bad Character Heuristic
The idea of bad character heuristic is simple. The character of the text which doesn’t match with the
current character of pattern is called the Bad Character. Upon mismatch we shift the pattern until –
1) The mismatch become a match
2) Pattern P move past the mismatch character.
Case 1 – Mismatch become match
We will lookup the position of last occurence of mismatching character in pattern and if mismatching
character exist in pattern then we’ll shift the pattern such that it get aligned to the mismatching character
in text T.

case 1

Explanation: In the above example, we got a mismatch at position 3. Here our mismatching character is
“A”. Now we will search for last occurence of “A” in pattern. We got “A” at position 1 in pattern
(displayed in Blue) and this is the last occurence of it. Now we will shift pattern 2 times so that “A” in
pattern get aligned with “A” in text.
Case 2 – Pattern move past the mismatch character
We’ll lookup the position of last occurence of mismatching character in pattern and if character does not
exist we will shift pattern past the mismatching character.
63
case2
Explanation: Here we have a mismatch at position 7. The mismatching character “C” does not exist in
pattern before position 7 so we’ll shift pattern past to the position 7 and eventually in above example we
have got a perfect match of pattern (displayed in Green). We are doing this because, “C” do not exist in
pattern so at every shift before position 7 we will get mismatch and our search will be fruitless.
In following implementation, we preprocess the pattern and store the last occurrence of every possible
character in an array of size equal to alphabet size. If the character is not present at all, then it may result
in a shift by m (length of pattern). Therefore, the bad character heuristic takes O(n/m) time in the best
case.

PROGRAM:

#include<string.h>
#include<stdio.h>
#include<conio.h>
char Dist[25],T[20],P[10];
int Last[10],d,m,n;
int BM(char T[],char P[])
{
int i,j,l;
m=strlen(P);
n=strlen(T);
distinctFn(T);
printf("\nLast(n)\n");
lastFn(P);
i=0;
while(i<n-m+1)
{
j=m-1;
for(;j>=0&&T[i+j]==P[j];j--)
{
if(j==0)
return i;
}

64
l=1+last(T[i+j]);
if(j>=l)
i+=j-l+1;
else
i=i+1;
}
return -1;
}
distinctFn(char T[])
{
int flag,i,k;
d=0;
for(i=0;i<n;i++)
{
flag=0;
for(k=0;k<d;k++)
{
if(T[i]==Dist[k])
flag=1;
}
if(flag==0)
Dist[d++]=T[i];
}
Dist[d]='\0';
}
lastFn(char P[])
{
int i,k;
for(i=0;i<d;i++)
Last[i]=-1;
for(i=0;i<d;i++)
{
for( k=n;k>=0;k--)
{
if(P[k]==Dist[i])
{
Last[i]=k;
break;
}
}
printf("%d ",Last[i]);
}
}
int last(char ch)
{
int i;
65
for(i=0;i<d;i++)
if(Dist[i]==ch)
return Last[i];
}
void main()
{
char text[25],pattern[10];
int index;
printf("Enter The Text :");
fflush(stdin);
scanf("%s",text);
printf("Enter The Pattern :");
scanf("%s",pattern);
index=BM(text,pattern);
if(index==-1)
printf("\nPattern Not Found In The Text");
else
printf("\nPattern Found In The Text At:%d",index);
getch();
}

OUTPUT:
Enter The Text :fromgietcse
Enter The Pattern :cse
Pattern Found In The Text At:8

EXPERIMENT-12: Program to implement pattern matching using knuth-morris-


pratt algorithm
DESCRIPTION:

Given a text txt[0..n-1] and a pattern pat[0..m-1], write a function search(char pat[], char txt[]) that
prints all occurrences of pat[] in txt[]. You may assume that n > m.
Examples:

Input: txt[] = "THIS IS A TEST TEXT"


pat[] = "TEST"
Output: Pattern found at index 10
Input: txt[] = "AABAACAADAABAABA"
pat[] = "AABA"
Output: Pattern found at index 0
Pattern found at index 9

66
Pattern found at index 12

Pattern searching is an important problem in computer science. When we do search for a string in
notepad/word file or browser or database, pattern searching algorithms are used to show the search
results.
We have discussed Naive pattern searching algorithm in the previous post. The worst case complexity of
the Naive algorithm is O(m(n-m+1)). The time complexity of KMP algorithm is O(n) in the worst case.
KMP (Knuth Morris Pratt) Pattern Searching
The Naive pattern searching algorithm doesn’t work well in cases where we see many matching
characters followed by a mismatching character. Following are some examples.
txt[] = "AAAAAAAAAAAAAAAAAB"
pat[] = "AAAAB"
txt[] = "ABABABCABABABCABABABC"
pat[] = "ABABAC" (not a worst case, but a bad case for Naive)

The KMP matching algorithm uses degenerating property (pattern having same sub-patterns appearing
more than once in the pattern) of the pattern and improves the worst case complexity to O(n). The basic
idea behind KMP’s algorithm is: whenever we detect a mismatch (after some matches), we already
know some of the characters in the text of next window. We take advantage of this information to avoid
matching the characters that we know will anyway match. Let us consider below example to understand
this.
PROGRAM:

#include<string.h>
#include<stdio.h>
#include<conio.h>
int Fail[10];
void FailureFn(char[]);
int KMP(char *T,char *P)
{
int i,j,m,n;
67
m=strlen(P);
n=strlen(T);
FailureFn(P);
i=0;
j=0;
while(i<n)
{
if(T[i]==P[j])
{
if(j==m-1)
return i-j;
else
{
i++;
j++;
}
}
else
{
if(j>0)
j=Fail[j-1];
else
i++;
}
}
return -1;
}
void FailureFn(char *P)
{
int m=strlen(P);
int i=1;
int j=0;
while(i<m)
{
if(P[i]==P[j])
{
Fail[i]=j+1;
i++;
j++;
}
else
if(j>0)
j=Fail[j-1];
else
{
Fail[j]=0;
68
i++;
}
}
}
void main()
{
char text[25],pattern[10];
int index;
clrscr();
printf("Enter The Text :");
fflush(stdin);
scanf("%s",text);
printf("Enter The Pattern :");
scanf("%s",pattern);
index=KMP(text,pattern);
if(index==-1)
printf("Pattern Not Found In The Text");
else
printf("Pattern Found In The Text At:%d",index);
getch();
}

OUTPUT:
Enter The Text :fromgietcse
Enter The Pattern :cse
Pattern Found In The Text At:8

EXPERIMENT-13: Program to implement priority queue


DESCRIPTION:
Overview:
Priority Queue is more specialized data structure than Queue. Like ordinary queue, priority queue has
same method but with a major difference. In Priority queue items are ordered by key value so that item
with the lowest value of key is at front and item with the highest value of key is at rear or vice versa. So
we're assigned priority to item based on its key value. Lower the value, higher the priority. Following are
the principal methods of a Priority Queue.
Basic Operations:
insert / enqueue − add an item to the rear of the queue.
remove / dequeue − remove an item from the front of the queue.
Insert / Enqueue Operation:
Whenever an element is inserted into queue, priority queue inserts the item according to its order. Here
we're assuming that data with high value has low priority.

69
Remove / Dequeue Operation:
Whenever an element is to be removed from queue, queue get the element using item count. Once element is
removed. Item count is reduced by one.

Applications:
1) CPU Scheduling
2) Graph algorithms like Dijkstra’s shortest path algorithm, Prim’s Minimum Spanning Tree, etc
3) All queue applications where priority is involved.

PROGRAM:

#include<stdio.h>
#include<conio.h>
#define max 15
int a[max],size=0;
void display()
{
int i;
for(i=1;i<=size;i++)
printf("%d ",a[i]);
}
void insert(int x)
{
int hole;
if(size==max-1)
printf("prority queue is full");
else
{
for(hole=++size;a[hole/2]>x && hole>1;hole=hole/2)
a[hole]=a[hole/2];
a[hole]=x;
}
70
}
int deletemin()
{
int child,x,hole=1,min=a[1];
if(size==0)
{
printf("queue is empty");
return 0;
}
else
{
x=a[size--];
for(child=1;child*2<=size;hole=child)
{
child=hole*2;
if(child<size&&a[child]>a[child+1])
child++;
if(x>a[child])
a[hole]=a[child];
else
break;
}
a[hole]=x;
}
return min;
}
main()
{
int ch,x;
clrscr();
do
{
printf("\n1.Insert\n2.Deletemin\n3.Display\n4.Exit\n");
scanf("%d",&ch);
switch(ch)
{
case 1:printf("enter Element\n");
scanf("%d",&x);
insert(x);
break;
case 2:x=deletemin();
printf("Deleted element is %d\n",x);
break;
case 3:display();
break;
case 4:exit(0);
71
}
}while(1);
}

OUTPUT:1.Insert

2.Deletemin
3.Display
4.Exit
1
enter Element
23

1.Insert
2.Deletemin
3.Display
4.Exit
1
enter Element
10

1.Insert
2.Deletemin
3.Display
4.Exit
1
enter Element
13

1.Insert
2.Deletemin
3.Display
4.Exit
1
enter Element
56

1.Insert
2.Deletemin
3.Display
4.Exit
2
Deleted element is 10
1.Insert
2.Deletemin
3.Display
72
4.Exit
2
Deleted element is 13

1.Insert
2.Deletemin
3.Display
4.Exit
3
23 56
1.Insert
2.Deletemin
3.Display
4.Exit
4
EXPERIMENT-14: Search Operation in SPLAY TREE

DESCRIPTION:
The search operation in Splay tree does the standard BST search, in addition to search, it also splays
(move a node to the root). If the search is successful, then the node that is found is splayed and becomes
the new root. Else the last node accessed prior to reaching the NULL is splayed and becomes the new
root.
There are following cases for the node being accessed.
1) Node is root We simply return the root, don’t do anything else as the accessed node is already root.
2) Zig: Node is child of root (the node has no grandparent). Node is either a left child of root (we do a
right rotation) or node is a right child of its parent (we do a left rotation).
T1, T2 and T3 are subtrees of the tree rooted with y (on left side) or x (on right side)
y x
/ \ Zig (Right Rotation) / \
x T3 – - – - – - – - - -> T1 y
/\ <--------- /\
T1 T2 Zag (Left Rotation) T2 T3
3) Node has both parent and grandparent. There can be following subcases.
3.a) Zig-Zig and Zag-Zag Node is left child of parent and parent is also left child of grand parent (Two
right rotations) OR node is right child of its parent and parent is also right child of grand parent (Two
Left Rotations).

Zig-Zig (Left Left Case):


G P X
/\ / \ /\
P T4 rightRotate(G) X G rightRotate(P) T1 P
/ \ ============> / \ / \ ============> /\
X T3 T1 T2 T3 T4 T2 G
/\ /\

73
T1 T2 T3 T4

Zag-Zag (Right Right Case):


G P X
/ \ / \ /\
T1 P leftRotate(G) G X leftRotate(P) P T4
/ \ ============> / \ / \ ============> / \
T2 X T1 T2 T3 T4 G T3
/\ /\
T3 T4 T1 T2
3.b) Zig-Zag and Zag-Zig Node is left child of parent and parent is right child of grand parent (Left
Rotation followed by right rotation) OR node is right child of its parent and parent is left child of grand
parent (Right Rotation followed by left rotation).
Zig-Zag (Left Right Case):
G G X
/\ / \ / \
P T4 leftRotate(P) X T4 rightRotate(G) P G
/ \ ============> / \ ============> / \ / \
T1 X P T3 T1 T2 T3 T4
/\ /\
T2 T3 T1 T2

Zag-Zig (Right Left Case):


G G X
/ \ / \ / \
T1 P rightRotate(P) T1 X leftRotate(P) G P
/ \ =============> / \ ============> / \ / \
X T4 T2 P T1 T2 T3 T4
/\ /\
T2 T3 T3 T4
Splay trees have excellent locality properties. Frequently accessed items are easy to find. Infrequent
items are out of way. All splay tree operations take O(Logn) time on average. Splay trees can be
rigorously shown to run in O(log n) average time per operation, over any sequence of operations
(assuming we start from an empty tree) Splay trees are simpler compared to AVL and Red-Black Trees
as no extra field is required in every tree node. Unlike AVL tree, a splay tree can change even with read-
only operations like search.

Applications of Splay Trees

Splay trees have become the most widely used basic data structure invented in the last 30 years, because
they're the fastest type of balanced search tree for many applications. Splay trees are used in Windows
NT (in the virtual memory, networking, and file system code), the gcc compiler and GNU C++ library,
the sed string editor, Fore Systems network routers, the most popular implementation of Unix malloc,
Linux loadable kernel modules, and in much other software
74
PROGRAM:

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

// An AVL tree node


struct node
{
int key;
struct node *left, *right;
};

/* Helper function that allocates a new node with the given key and
NULL left and right pointers. */
struct node* newNode(int key)
{
struct node* node = (struct node*)malloc(sizeof(struct node));
node->key = key;
node->left = node->right = NULL;
return (node);
}

// A utility function to right rotate subtree rooted with y


// See the diagram given above.
struct node *rightRotate(struct node *x)
{
struct node *y = x->left;
x->left = y->right;
y->right = x;
return y;
}

// A utility function to left rotate subtree rooted with x


// See the diagram given above.
struct node *leftRotate(struct node *x)
{
struct node *y = x->right;
x->right = y->left;
y->left = x;
return y;
}

// This function brings the key at root if key is present in tree.


// If key is not present, then it brings the last accessed item at
// root. This function modifies the tree and returns the new root
75
struct node *splay(struct node *root, int key)
{
// Base cases: root is NULL or key is present at root
if (root == NULL || root->key == key)
return root;

// Key lies in left subtree


if (root->key > key)
{
// Key is not in tree, we are done
if (root->left == NULL) return root;

// Zig-Zig (Left Left)


if (root->left->key > key)
{
// First recursively bring the key as root of left-left
root->left->left = splay(root->left->left, key);

// Do first rotation for root, second rotation is done after else


root = rightRotate(root);
}
else if (root->left->key < key) // Zig-Zag (Left Right)
{
// First recursively bring the key as root of left-right
root->left->right = splay(root->left->right, key);

// Do first rotation for root->left


if (root->left->right != NULL)
root->left = leftRotate(root->left);
}

// Do second rotation for root


return (root->left == NULL)? root: rightRotate(root);
}
else // Key lies in right subtree
{
// Key is not in tree, we are done
if (root->right == NULL) return root;

// Zag-Zig (Right Left)


if (root->right->key > key)
{
// Bring the key as root of right-left
root->right->left = splay(root->right->left, key);

// Do first rotation for root->right


76
if (root->right->left != NULL)
root->right = rightRotate(root->right);
}
else if (root->right->key < key)// Zag-Zag (Right Right)
{
// Bring the key as root of right-right and do first rotation
root->right->right = splay(root->right->right, key);
root = leftRotate(root);
}

// Do second rotation for root


return (root->right == NULL)? root: leftRotate(root);
}
}

// The search function for Splay tree. Note that this function
// returns the new root of Splay Tree. If key is present in tree
// then, it is moved to root.
struct node *search(struct node *root, int key)
{
return splay(root, key);
}

// A utility function to print preorder traversal of the tree.


// The function also prints height of every node
void preOrder(struct node *root)
{
if (root != NULL)
{
printf("%d ", root->key);
preOrder(root->left);
preOrder(root->right);
}
}

/* Drier program to test above function*/


int main()
{
struct node *root = newNode(100);
root->left = newNode(50);
root->right = newNode(200);
root->left->left = newNode(40);
root->left->left->left = newNode(30);
root->left->left->left->left = newNode(20);
root = search(root, 20);
printf("Preorder traversal of the modified Splay tree is \n");
77
preOrder(root);
return 0;
}

OUTPUT:
Preorder traversal of the modified Splay tree is 20 50 30 40 100 200

EXPERIMENT-15: implementation of Red-Black Tree Insertion

DESCRIPTION:
In AVL tree insertion, we used rotation as a tool to do balancing after insertion caused imbalance. In
Red-Black tree, we use two tools to do balancing.
1) Recoloring
2) Rotation
We try recoloring first, if recoloring doesn’t work, then we go for rotation. Following is detailed
algorithm. The algorithms has mainly two cases depending upon the color of uncle. If uncle is red, we
do recoloring. If uncle is black, we do rotations and/or recoloring.
Color of a NULL node is considered as BLACK.
Let x be the newly inserted node.
1) Perform standard BST insertion and make the color of newly inserted nodes as RED.
2) If x is root, change color of x as BLACK (Black height of complete tree increases by 1).
3) Do following if color of x’s parent is not BLACK or x is not root.
a) If x’s uncle is RED (Grand parent must have been black from property 4)
(i) Change color of parent and uncle as BLACK.
(ii) color of grand parent as RED.
(iii) Change x = x’s grandparent, repeat steps 2 and 3 for new x
b) If x’s uncle is BLACK, then there can be four configurations for x, x’s parent (p) and x’s grandparent
(g) (This is similar to AVL Tree)
i) Left Left Case (p is left child of g and x is left child of p).
ii) Left Right Case (p is left child of g and x is right child of p)
iii) Right Right Case (Mirror of case a)
iv) Right Left Case (Mirror of case c)
Example of Insetion:

78
PROGRAM:
/** C++ implementation for Red-Black Tree Insertion
This code is adopted from the code provided by
Dinesh Khandelwal in comments **/
#include <bits/stdc++.h>
using namespace std;

enum Color {RED, BLACK};

struct Node
{
int data;
bool color;
Node *left, *right, *parent;

// Constructor
Node(int data)
{
this->data = data;
left = right = parent = NULL;
}
};

// Class to represent Red-Black Tree


class RBTree
{
private:
Node *root;
protected:
void rotateLeft(Node *&, Node *&);
void rotateRight(Node *&, Node *&);
void fixViolation(Node *&, Node *&);
public:
// Constructor
RBTree() { root = NULL; }
79
void insert(const int &n);
void inorder();
void levelOrder();
};

// A recursive function to do level order traversal


void inorderHelper(Node *root)
{
if (root == NULL)
return;

inorderHelper(root->left);
cout << root->data << " ";
inorderHelper(root->right);
}

/* A utility function to insert a new node with given key


in BST */
Node* BSTInsert(Node* root, Node *pt)
{
/* If the tree is empty, return a new node */
if (root == NULL)
return pt;

/* Otherwise, recur down the tree */


if (pt->data < root->data)
{
root->left = BSTInsert(root->left, pt);
root->left->parent = root;
}
else if (pt->data > root->data)
{
root->right = BSTInsert(root->right, pt);
root->right->parent = root;
}

/* return the (unchanged) node pointer */


return root;
}

// Utility function to do level order traversal


void levelOrderHelper(Node *root)
{
if (root == NULL)
return;

80
std::queue<Node *> q;
q.push(root);

while (!q.empty())
{
Node *temp = q.front();
cout << temp->data << " ";
q.pop();

if (temp->left != NULL)
q.push(temp->left);

if (temp->right != NULL)
q.push(temp->right);
}
}

void RBTree::rotateLeft(Node *&root, Node *&pt)


{
Node *pt_right = pt->right;

pt->right = pt_right->left;

if (pt->right != NULL)
pt->right->parent = pt;

pt_right->parent = pt->parent;

if (pt->parent == NULL)
root = pt_right;

else if (pt == pt->parent->left)


pt->parent->left = pt_right;

else
pt->parent->right = pt_right;

pt_right->left = pt;
pt->parent = pt_right;
}

void RBTree::rotateRight(Node *&root, Node *&pt)


{
Node *pt_left = pt->left;

pt->left = pt_left->right;
81
if (pt->left != NULL)
pt->left->parent = pt;

pt_left->parent = pt->parent;

if (pt->parent == NULL)
root = pt_left;

else if (pt == pt->parent->left)


pt->parent->left = pt_left;

else
pt->parent->right = pt_left;

pt_left->right = pt;
pt->parent = pt_left;
}

// This function fixes violations caused by BST insertion


void RBTree::fixViolation(Node *&root, Node *&pt)
{
Node *parent_pt = NULL;
Node *grand_parent_pt = NULL;

while ((pt != root) && (pt->color != BLACK) &&


(pt->parent->color == RED))
{

parent_pt = pt->parent;
grand_parent_pt = pt->parent->parent;

/* Case : A
Parent of pt is left child of Grand-parent of pt */
if (parent_pt == grand_parent_pt->left)
{

Node *uncle_pt = grand_parent_pt->right;

/* Case : 1
The uncle of pt is also red
Only Recoloring required */
if (uncle_pt != NULL && uncle_pt->color == RED)
{
grand_parent_pt->color = RED;
parent_pt->color = BLACK;
82
uncle_pt->color = BLACK;
pt = grand_parent_pt;
}

else
{
/* Case : 2
pt is right child of its parent
Left-rotation required */
if (pt == parent_pt->right)
{
rotateLeft(root, parent_pt);
pt = parent_pt;
parent_pt = pt->parent;
}

/* Case : 3
pt is left child of its parent
Right-rotation required */
rotateRight(root, grand_parent_pt);
swap(parent_pt->color, grand_parent_pt->color);
pt = parent_pt;
}
}

/* Case : B
Parent of pt is right child of Grand-parent of pt */
else
{
Node *uncle_pt = grand_parent_pt->left;

/* Case : 1
The uncle of pt is also red
Only Recoloring required */
if ((uncle_pt != NULL) && (uncle_pt->color == RED))
{
grand_parent_pt->color = RED;
parent_pt->color = BLACK;
uncle_pt->color = BLACK;
pt = grand_parent_pt;
}
else
{
/* Case : 2
pt is left child of its parent
Right-rotation required */
83
if (pt == parent_pt->left)
{
rotateRight(root, parent_pt);
pt = parent_pt;
parent_pt = pt->parent;
}

/* Case : 3
pt is right child of its parent
Left-rotation required */
rotateLeft(root, grand_parent_pt);
swap(parent_pt->color, grand_parent_pt->color);
pt = parent_pt;
}
}
}

root->color = BLACK;
}

// Function to insert a new node with given data


void RBTree::insert(const int &data)
{
Node *pt = new Node(data);

// Do a normal BST insert


root = BSTInsert(root, pt);

// fix Red Black Tree violations


fixViolation(root, pt);
}

// Function to do inorder and level order traversals


void RBTree::inorder() { inorderHelper(root);}
void RBTree::levelOrder() { levelOrderHelper(root); }

// Driver Code
int main()
{
RBTree tree;

tree.insert(7);
tree.insert(6);
tree.insert(5);
tree.insert(4);
tree.insert(3);
84
tree.insert(2);
tree.insert(1);

cout << "Inoder Traversal of Created Tree\n";


tree.inorder();

cout << "\n\nLevel Order Traversal of Created Tree\n";


tree.levelOrder();

return 0;
}
OUTPUT:
Inoder Traversal of Created Tree
1 2 3 4 5 6 7

Level Order Traversal of Created Tree


6 4 7 2 5 1 3

EXPERIMENT-16: C program for Fibonacci Search

Algorithm:
Let the searched element be x.
The idea is to first find the smallest Fibonacci number that is greater than or equal to the length of given
array. Let the found Fibonacci number be fib (m’th Fibonacci number). We use (m-2)’th Fibonacci
number as the index (If it is a valid index). Let (m-2)’th Fibonacci Number be i, we compare arr[i] with
x, if x is same, we return i. Else if x is greater, we recur for subarray after i, else we recur for subarray
before i.
Below is the complete algorithm
Let arr[0..n-1] be the input array and element to be searched be x.
1. Find the smallest Fibonacci Number greater than or equal to n. Let this number be fibM [m’th
Fibonacci Number]. Let the two Fibonacci numbers preceding it be fibMm1 [(m-1)’th Fibonacci
Number] and fibMm2 [(m-2)’th Fibonacci Number].
2. While the array has elements to be inspected:
1. Compare x with the last element of the range covered by fibMm2
2. If x matches, return index
3. Else If x is less than the element, move the three Fibonacci variables two Fibonacci
down, indicating elimination of approximately rear two-third of the remaining array.
4. Else x is greater than the element, move the three Fibonacci variables one Fibonacci
down. Reset offset to index. Together these indicate elimination of approximately front
one-third of the remaining array.
3. Since there might be a single element remaining for comparison, check if fibMm1 is 1. If Yes,
compare x with that remaining element. If match, return index.

PROGRAM:

85
#include <stdio.h>
// Utility function to find minimum of two elements
int min(int x, int y) { return (x<=y)? x : y; }
/* Returns index of x if present, else returns -1 */
int fibMonaccianSearch(int arr[], int x, int n)
{
/* Initialize fibonacci numbers */
int fibMMm2 = 0; // (m-2)'th Fibonacci No.
int fibMMm1 = 1; // (m-1)'th Fibonacci No.
int fibM = fibMMm2 + fibMMm1; // m'th Fibonacci

/* fibM is going to store the smallest Fibonacci


Number greater than or equal to n */
while (fibM < n)
{
fibMMm2 = fibMMm1;
fibMMm1 = fibM;
fibM = fibMMm2 + fibMMm1;
}

// Marks the eliminated range from front


int offset = -1;

/* while there are elements to be inspected. Note that


we compare arr[fibMm2] with x. When fibM becomes 1,
fibMm2 becomes 0 */
while (fibM > 1)
{
// Check if fibMm2 is a valid location
int i = min(offset+fibMMm2, n-1);

/* If x is greater than the value at index fibMm2,


cut the subarray array from offset to i */
if (arr[i] < x)
{
fibM = fibMMm1;
fibMMm1 = fibMMm2;
fibMMm2 = fibM - fibMMm1;
offset = i;
}

/* If x is greater than the value at index fibMm2,


cut the subarray after i+1 */
else if (arr[i] > x)
{
fibM = fibMMm2;
86
fibMMm1 = fibMMm1 - fibMMm2;
fibMMm2 = fibM - fibMMm1;
}

/* element found. return index */


else return i;
}

/* comparing the last element with x */


if(fibMMm1 && arr[offset+1]==x)return offset+1;

/*element not found. return -1 */


return -1;
}
/* driver function */
int main(void)
{
int arr[] = {10, 22, 35, 40, 45, 50, 80, 82,85, 90, 100};
int n = sizeof(arr)/sizeof(arr[0]);
int x = 85;
printf("Found at index: %d",
fibMonaccianSearch(arr, x, n));
return 0;
}
OUTPUT:
Found at index: 8

EXPERIMENT-17: Largest subarray with equal number of 0s and 1s.

DESCRIPTION:
Given an array containing only 0s and 1s, find the largest subarray which contain equal no of 0s and 1s.
Expected time complexity is O(n).
Examples:
Input: arr[] = {1, 0, 1, 1, 1, 0, 0}
Output: 1 to 6 (Starting and Ending indexes of output subarray)
Input: arr[] = {1, 1, 1, 1}
Output: No such subarray
Input: arr[] = {0, 0, 1, 1, 0}
Output: 0 to 3 Or 1 to 4
Method:
A simple method is to use two nested loops. The outer loop picks a starting point i. The inner loop
considers all subarrays starting from i. If size of a subarray is greater than maximum size so far,
then update the maximum size. In the below code, 0s are considered as -1 and sum of all values
from i to j is calculated. If sum becomes 0, then size of this subarray is compared with largest size
so far.

87
PROGRAM:

#include <stdio.h>

// This function Prints the starting and ending


// indexes of the largest subarray with equal
// number of 0s and 1s. Also returns the size
// of such subarray.

int findSubArray(int arr[], int n)


{
int sum = 0;
int maxsize = -1, startindex;

// Pick a starting point as i

for (int i = 0; i < n-1; i++)


{
sum = (arr[i] == 0)? -1 : 1;

// Consider all subarrays starting from i

for (int j = i+1; j < n; j++)


{
(arr[j] == 0)? (sum += -1): (sum += 1);

// If this is a 0 sum subarray, then


// compare it with maximum size subarray
// calculated so far

if (sum == 0 && maxsize < j-i+1)


{
maxsize = j - i + 1;
startindex = i;
}
}
}
if (maxsize == -1)
printf("No such subarray");
else
printf("%d to %d", startindex, startindex+maxsize-1);

return maxsize;
}

88
/* Driver program to test above functions*/

int main()
{
int arr[] = {1, 0, 0, 1, 0, 1, 1};
int size = sizeof(arr)/sizeof(arr[0]);

findSubArray(arr, size);
return 0;
}

OUTPUT:
0 to 5

EXPERIMENT-18: A union-find algorithm to detect cycle in a graph.

DESCRIPTION:
A disjoint-set data structure is a data structure that keeps track of a set of elements partitioned into a
number of disjoint (non-overlapping) subsets. A union-find algorithm is an algorithm that performs two
useful operations on such a data structure:
Find: Determine which subset a particular element is in. This can be used for determining if two
elements are in the same subset.
Union: Join two subsets into a single subset.
In this post, we will discuss an application of Disjoint Set Data Structure. The application is to check
whether a given graph contains a cycle or not.
Union-Find Algorithm can be used to check whether an undirected graph contains cycle or not. Note that
we have discussed an algorithm to detect cycle. This is another method based on Union-Find. This
method assumes that graph doesn’t contain any self-loops.
We can keep track of the subsets in a 1D array, let’s call it parent[].
Let us consider the following graph:

For each edge, make subsets using both the vertices of the edge. If both the vertices are in the same
subset, a cycle is found.
Initially, all slots of parent array are initialized to -1 (means there is only one item in every subset).

0 1 2
-1 -1 -1

Now process all edges one by one.


89
Edge 0-1: Find the subsets in which vertices 0 and 1 are. Since they are in different subsets, we take the
union of them. For taking the union, either make node 0 as parent of node 1 or vice-versa.
0 1 2 <----- 1 is made parent of 0 (1 is now representative of subset {0, 1})
1 -1 -1

Edge 1-2: 1 is in subset 1 and 2 is in subset 2. So, take union.


0 1 2 <----- 2 is made parent of 1 (2 is now representative of subset {0, 1, 2})
1 2 -1

Edge 0-2: 0 is in subset 2 and 2 is also in subset 2. Hence, including this edge forms a cycle.

PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// a structure to represent an edge in the graph


struct Edge
{
int src, dest;
};

// a structure to represent a graph


struct Graph
{
// V-> Number of vertices, E-> Number of edges
int V, E;

// graph is represented as an array of edges


struct Edge* edge;
};

// Creates a graph with V vertices and E edges


struct Graph* createGraph(int V, int E)
{
struct Graph* graph =
(struct Graph*) malloc( sizeof(struct Graph) );
graph->V = V;
graph->E = E;

graph->edge =
(struct Edge*) malloc( graph->E * sizeof( struct Edge ) );

return graph;
90
}

// A utility function to find the subset of an element i


int find(int parent[], int i)
{
if (parent[i] == -1)
return i;
return find(parent, parent[i]);
}

// A utility function to do union of two subsets


void Union(int parent[], int x, int y)
{
int xset = find(parent, x);
int yset = find(parent, y);
parent[xset] = yset;
}
// The main function to check whether a given graph contains
// cycle or not
int isCycle( struct Graph* graph )
{
// Allocate memory for creating V subsets
int *parent = (int*) malloc( graph->V * sizeof(int) );

// Initialize all subsets as single element sets


memset(parent, -1, sizeof(int) * graph->V);

// Iterate through all edges of graph, find subset of both


// vertices of every edge, if both subsets are same, then
// there is cycle in graph.
for(int i = 0; i < graph->E; ++i)
{
int x = find(parent, graph->edge[i].src);
int y = find(parent, graph->edge[i].dest);

if (x == y)
return 1;

Union(parent, x, y);
}
return 0;
}

// Driver program to test above functions


int main()
{
91
/* Let us create the following graph
0
| \
| \
1-----2 */
int V = 3, E = 3;
struct Graph* graph = createGraph(V, E);

// add edge 0-1


graph->edge[0].src = 0;
graph->edge[0].dest = 1;

// add edge 1-2


graph->edge[1].src = 1;
graph->edge[1].dest = 2;

// add edge 0-2


graph->edge[2].src = 0;
graph->edge[2].dest = 2;

if (isCycle(graph))
printf( "graph contains cycle" );
else
printf( "graph doesn't contain cycle" );

return 0;
}
OUTPUT:
graph contains cycle

EXPERIMENT-19: Merge Two Balanced Binary Search Trees.

DESCRIPTION:
You are given two balanced binary search trees e.g., AVL or Red Black Tree. Write a function that
merges the two given balanced BSTs into a balanced binary search tree. Let there be m elements
in first tree and n elements in the other tree. Your merge function should take O(m+n) time.
In the following solutions, it is assumed that sizes of trees are also given as input. If the size is not
given, then we can get the size by traversing the tree.

Method 1 (Insert elements of first tree to second)


Take all elements of first BST one by one, and insert them into the second BST. Inserting an
element to a self balancing BST takes Log n time where n is size of the BST. So time complexity
of this method is Log(n) + Log(n+1) … Log(m+n-1). The value of this expression will be
between mLogn and mLog(m+n-1). As an optimization, we can pick the smaller tree as first tree.

92
Method 2 (Merge Inorder Traversals)
1) Do inorder traversal of first tree and store the traversal in one temp array arr1[]. This step takes
O(m) time.
2) Do inorder traversal of second tree and store the traversal in another temp array arr2[]. This
step takes O(n) time.
3) The arrays created in step 1 and 2 are sorted arrays. Merge the two sorted arrays into one array
of size m + n. This step takes O(m+n) time.
4) Construct a balanced tree from the merged array using the technique discussed in this post.
This step takes O(m+n) time.
Time complexity of this method is O(m+n) which is better than method 1. This method takes
O(m+n) time even if the input BSTs are not balanced.

PROGRAM:

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

/* A binary tree node has data, pointer to left child


and a pointer to right child */
struct node
{
int data;
struct node* left;
struct node* right;
};

// A utility unction to merge two sorted arrays into one


int *merge(int arr1[], int arr2[], int m, int n);

// A helper function that stores inorder traversal of a tree in inorder array


void storeInorder(struct node* node, int inorder[], int *index_ptr);

/* A function that constructs Balanced Binary Search Tree from a sorted array
See https://www.geeksforgeeks.org/archives/17138 */
struct node* sortedArrayToBST(int arr[], int start, int end);

/* This function merges two balanced BSTs with roots as root1 and root2.
m and n are the sizes of the trees respectively */
struct node* mergeTrees(struct node *root1, struct node *root2, int m, int n)
{
// Store inorder traversal of first tree in an array arr1[]
int *arr1 = new int[m];
int i = 0;
storeInorder(root1, arr1, &i);

// Store inorder traversal of second tree in another array arr2[]


93
int *arr2 = new int[n];
int j = 0;
storeInorder(root2, arr2, &j);

// Merge the two sorted array into one


int *mergedArr = merge(arr1, arr2, m, n);

// Construct a tree from the merged array and return root of the tree
return sortedArrayToBST (mergedArr, 0, m+n-1);
}

/* Helper function that allocates a new node with the


given data and NULL left and right pointers. */
struct node* newNode(int data)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;

return(node);
}

// A utility function to print inorder traversal of a given binary tree


void printInorder(struct node* node)
{
if (node == NULL)
return;

/* first recur on left child */


printInorder(node->left);

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

/* now recur on right child */


printInorder(node->right);
}

// A utility unction to merge two sorted arrays into one


int *merge(int arr1[], int arr2[], int m, int n)
{
// mergedArr[] is going to contain result
int *mergedArr = new int[m + n];
int i = 0, j = 0, k = 0;

94
// Traverse through both arrays
while (i < m && j < n)
{
// Pick the smaler element and put it in mergedArr
if (arr1[i] < arr2[j])
{
mergedArr[k] = arr1[i];
i++;
}
else
{
mergedArr[k] = arr2[j];
j++;
}
k++;
}

// If there are more elements in first array


while (i < m)
{
mergedArr[k] = arr1[i];
i++; k++;
}

// If there are more elements in second array


while (j < n)
{
mergedArr[k] = arr2[j];
j++; k++;
}

return mergedArr;
}

// A helper function that stores inorder traversal of a tree rooted with node
void storeInorder(struct node* node, int inorder[], int *index_ptr)
{
if (node == NULL)
return;

/* first recur on left child */


storeInorder(node->left, inorder, index_ptr);

inorder[*index_ptr] = node->data;
(*index_ptr)++; // increase index for next entry

95
/* now recur on right child */
storeInorder(node->right, inorder, index_ptr);
}

/* A function that constructs Balanced Binary Search Tree from a sorted array
struct node* sortedArrayToBST(int arr[], int start, int end)
{
/* Base Case */
if (start > end)
return NULL;

/* Get the middle element and make it root */


int mid = (start + end)/2;
struct node *root = newNode(arr[mid]);

/* Recursively construct the left subtree and make it


left child of root */
root->left = sortedArrayToBST(arr, start, mid-1);

/* Recursively construct the right subtree and make it


right child of root */
root->right = sortedArrayToBST(arr, mid+1, end);

return root;
}

/* Driver program to test above functions*/


int main()
{
/* Create following tree as first balanced BST
100
/ \
50 300
/\
20 70
*/
struct node *root1 = newNode(100);
root1->left = newNode(50);
root1->right = newNode(300);
root1->left->left = newNode(20);
root1->left->right = newNode(70);

/* Create following tree as second balanced BST


80
/ \
40 120
96
*/
struct node *root2 = newNode(80);
root2->left = newNode(40);
root2->right = newNode(120);

struct node *mergedTree = mergeTrees(root1, root2, 5, 3);

printf ("Following is Inorder traversal of the merged tree \n");


printInorder(mergedTree);

getchar();
return 0;
}

OUTPUT:
Following is Inorder traversal of the merged tree
20 40 50 70 80 100 120 300

EXPERIMENT-20: How to handle duplicates in Binary Search Tree?

DESCRIPTION:
In a Binary Search Tree (BST), all keys in left subtree of a key must be smaller and all keys in right
subtree must be greater. So a Binary Search Tree by definition has distinct keys.
How to allow duplicates where every insertion inserts one more key with a value and every deletion
deletes one occurrence?
A Simple Solution is to allow same keys on right side (we could also choose left side). For example
consider insertion of keys 12, 10, 20, 9, 11, 10, 12, 12 in an empty Binary Search Tree
12
/ \
10 20
/ \ /
9 11 12
/ \
10 12
A Better Solution is to augment every tree node to store count together with regular fields like key, left
and right pointers.
Insertion of keys 12, 10, 20, 9, 11, 10, 12, 12 in an empty Binary Search Tree would create following.
12(3)
/ \
10(2) 20(1)
/ \
9(1) 11(1)
97
Count of a key is shown in bracket
This approach has following advantages over above simple approach.
1) Height of tree is small irrespective of number of duplicates. Note that most of the BST operations
(search, insert and delete) have time complexity as O(h) where h is height of BST. So if we are able
to keep the height small, we get advantage of less number of key comparisons.
2) Search, Insert and Delete become easier to do. We can use same insert, search and delete algorithms
with small modifications (see below code).
3) This approach is suited for self-balancing BSTs (AVL Tree, Red-Black Tree, etc) also. These trees
involve rotations, and a rotation may violate BST property of simple solution as a same key can be
in either left side or right side after rotation.

PROGRAM :
// C program to implement basic operations (search, insert and delete)
// on a BST that handles duplicates by storing count with every node
#include<stdio.h>
#include<stdlib.h>

struct node
{
int key;
int count;
struct node *left, *right;
};

// A utility function to create a new BST node


struct node *newNode(int item)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->key = item;
temp->left = temp->right = NULL;
temp->count = 1;
return temp;
}

// A utility function to do inorder traversal of BST


void inorder(struct node *root)
{
if (root != NULL)
{
inorder(root->left);
printf("%d(%d) ", root->key, root->count);
inorder(root->right);
}
}

98
/* A utility function to insert a new node with given key in BST */
struct node* insert(struct node* node, int key)
{
/* If the tree is empty, return a new node */
if (node == NULL) return newNode(key);

// If key already exists in BST, icnrement count and return


if (key == node->key)
{
(node->count)++;
return node;
}

/* Otherwise, recur down the tree */


if (key < node->key)
node->left = insert(node->left, key);
else
node->right = insert(node->right, key);

/* return the (unchanged) node pointer */


return node;
}

/* Given a non-empty binary search tree, return the node with


minimum key value found in that tree. Note that the entire
tree does not need to be searched. */
struct node * minValueNode(struct node* node)
{
struct node* current = node;

/* loop down to find the leftmost leaf */


while (current->left != NULL)
current = current->left;

return current;
}

/* Given a binary search tree and a key, this function


deletes a given key and returns root of modified tree */
struct node* deleteNode(struct node* root, int key)
{
// base case
if (root == NULL) return root;

// If the key to be deleted is smaller than the


// root's key, then it lies in left subtree
99
if (key < root->key)
root->left = deleteNode(root->left, key);

// If the key to be deleted is greater than the root's key,


// then it lies in right subtree
else if (key > root->key)
root->right = deleteNode(root->right, key);

// if key is same as root's key


else
{
// If key is present more than once, simply decrement
// count and return
if (root->count > 1)
{
(root->count)--;
return root;
}

// ElSE, delete the node

// node with only one child or no child


if (root->left == NULL)
{
struct node *temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL)
{
struct node *temp = root->left;
free(root);
return temp;
}

// node with two children: Get the inorder successor (smallest


// in the right subtree)
struct node* temp = minValueNode(root->right);

// Copy the inorder successor's content to this node


root->key = temp->key;

// Delete the inorder successor


root->right = deleteNode(root->right, temp->key);
}
return root;
100
}

// Driver Program to test above functions


int main()
{
/* Let us create following BST
12(3)
/ \
10(2) 20(1)
/ \
9(1) 11(1) */
struct node *root = NULL;
root = insert(root, 12);
root = insert(root, 10);
root = insert(root, 20);
root = insert(root, 9);
root = insert(root, 11);
root = insert(root, 10);
root = insert(root, 12);
root = insert(root, 12);

printf("Inorder traversal of the given tree \n");


inorder(root);

printf("\nDelete 20\n");
root = deleteNode(root, 20);
printf("Inorder traversal of the modified tree \n");
inorder(root);

printf("\nDelete 12\n");
root = deleteNode(root, 12);
printf("Inorder traversal of the modified tree \n");
inorder(root);

printf("\nDelete 9\n");
root = deleteNode(root, 9);
printf("Inorder traversal of the modified tree \n");
inorder(root);

return 0;
}

OUTPUT:
Inorder traversal of the given tree
9(1) 10(2) 11(1) 12(3) 20(1)

101
Delete 20
Inorder traversal of the modified tree
9(1) 10(2) 11(1) 12(3)
Delete 12
Inorder traversal of the modified tree
9(1) 10(2) 11(1) 12(2)
Delete 9
Inorder traversal of the modified tree
10(2) 11(1) 12(2)

EXPERIMENT-21: Count smaller elements on right side.

DESCRIPTION:
Write a function to count number of smaller elements on right of each element in an array. Given an
unsorted array arr[] of distinct integers, construct another array countSmaller[] such that
countSmaller[i] contains count of smaller elements on right side of each element arr[i] in array.
Examples:
Input: arr[] = {12, 1, 2, 3, 0, 11, 4}
Output: countSmaller[] = {6, 1, 1, 1, 0, 1, 0}
(Corner Cases)
Input: arr[] = {5, 4, 3, 2, 1}
Output: countSmaller[] = {4, 3, 2, 1, 0}
Input: arr[] = {1, 2, 3, 4, 5}
Output: countSmaller[] = {0, 0, 0, 0, 0}
Method:
Use two loops. The outer loop picks all elements from left to right. The inner loop iterates through
all the elements on right side of the picked element and updates countSmaller[].

Input: arr[] = {12, 1, 2, 3, 0, 11, 4}


Output: countSmaller[] = {6, 1, 1, 1, 0, 1, 0}
(Corner Cases)
Input: arr[] = {5, 4, 3, 2, 1}
Output: countSmaller[] = {4, 3, 2, 1, 0}
Input: arr[] = {1, 2, 3, 4, 5}
Output: countSmaller[] = {0, 0, 0, 0, 0}

PROGRAM:

102
void constructLowerArray (int *arr[], int *countSmaller, int n)
{
int i, j;

// initialize all the counts in countSmaller array as 0


for (i = 0; i < n; i++)
countSmaller[i] = 0;

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


{
for (j = i+1; j < n; j++)
{
if (arr[j] < arr[i])
countSmaller[i]++;
}
}
}

/* Utility function that prints out an array on a line */


void printArray(int arr[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", arr[i]);

printf("\n");
}

// Driver program to test above functions


int main()
{
int arr[] = {12, 10, 5, 4, 2, 20, 6, 1, 0, 2};
int n = sizeof(arr)/sizeof(arr[0]);
int *low = (int *)malloc(sizeof(int)*n);
constructLowerArray(arr, low, n);
printArray(low, n);
return 0;
}
OUTPUT:

Following is the constructed smaller count array

3122200

EXPERIMENT-22: Find shortest unique prefix for every word in a given list.

103
DESCRIPTION:
Given an array of words, find all shortest unique prefixes to represent each word in the given array.
Assume that no word is prefix of another.
Examples:
Input: arr[] = {"zebra", "dog", "duck", "dove"}
Output: dog, dov, du, z
Explanation: dog => dog
dove = dov
duck = du
z => zebra
Input: arr[] = {"geeksgeeks", "geeksquiz", "geeksforgeeks"};
Output: geeksf, geeksg, geeksq}

A Simple Solution is to consider every prefix of every word (starting from the shortest to largest), and if
a prefix is not prefix of any other string, then print it.
An Efficient Solution is to use Trie. The idea is to maintain a count in every node. Below are steps.
1) Construct a Trie of all words. Also maintain frequency of every node (Here frequency is number of
times node is visited during insertion). Time complexity of this step is O(N) where N is total number of
characters in all words.
2) Now, for every word, we find the character nearest to the root with frequency as 1. The prefix of the
word is path from root to this character. To do this, we can traverse Trie starting from root. For every
node being traversed, we check its frequency. If frequency is one, we print all characters from root to
this node and don’t traverse down this node.
Time complexity if this step also is O(N) where N is total number of characters in all words.
root
/\
(d, 3)/ \(z, 1)
/ \
Node1 Node2
/\ \
(o,2)/ \(u,1) \(e,1)
/ \ \
Node1.1 Node1.2 Node2.1
/ \ \ \
(g,1)/ \ (t,1) \(c,1) \(b,1)
/ \ \ \
Leaf Leaf Node1.2.1 Node2.1.1
(dog) (dot) \ \
\(k, 1) \(r, 1)

104
\ \
Leaf Node2.1.1.1
(duck) \
\(a,1)
\
Leaf
(zebra)

PROGRAM:
// uniquely reprsent words.
#include<bits/stdc++.h>
using namespace std;

#define MAX 256

// Maximum length of an input word


#define MAX_WORD_LEN 500

// Trie Node.
struct trieNode
{
struct trieNode *child[MAX];
int freq; // To store frequency
};

// Function to create a new trie node.


struct trieNode *newTrieNode(void)
{
struct trieNode *newNode = new trieNode;
newNode->freq = 1;
for (int i = 0; i<MAX; i++)
newNode->child[i] = NULL;
return newNode;
}

// Method to insert a new string into Trie


void insert(struct trieNode *root, string str)
{
// Length of the URL
int len = str.length();
struct trieNode *pCrawl = root;

// Traversing over the length of given str.


for (int level = 0; level<len; level++)
105
{
// Get index of child node from current character
// in str.
int index = str[level];

// Create a new child if not exist already


if (!pCrawl->child[index])
pCrawl->child[index] = newTrieNode();
else
(pCrawl->child[index]->freq)++;

// Move to the child


pCrawl = pCrawl->child[index];
}
}

// This function prints unique prefix for every word stored


// in Trie. Prefixes one by one are stored in prefix[].
// 'ind' is current index of prefix[]
void findPrefixesUtil(struct trieNode *root, char prefix[],
int ind)
{
// Corner case
if (root == NULL)
return;

// Base case
if (root->freq == 1)
{
prefix[ind] = '\0';
cout << prefix << " ";
return;
}

for (int i=0; i<MAX; i++)


{
if (root->child[i] != NULL)
{
prefix[ind] = i;
findPrefixesUtil(root->child[i], prefix, ind+1);
}
}
}

// Function to print all prefixes that uniquely


// represent all words in arr[0..n-1]
106
void findPrefixes(string arr[], int n)
{
// Construct a Trie of all words
struct trieNode *root = newTrieNode();
root->freq = 0;
for (int i = 0; i<n; i++)
insert(root, arr[i]);

// Create an array to store all prefixes


char prefix[MAX_WORD_LEN];

// Print all prefixes using Trie Traversal


findPrefixesUtil(root, prefix, 0);
}

// Driver function.
int main()
{
string arr[] = {"zebra", "dog", "duck", "dove"};
int n = sizeof(arr)/sizeof(arr[0]);
findPrefixes(arr, n);

return 0;
}
OUTPUT:
dog dov du z

EXPERIMENT-23: Implement a Phone Directory


DESCRIPTION:
Given a list of contacts which exist in a phone directory. The task is to implement search query for the
phone directory. The search query on a string ‘str’ displays all the contacts which prefix as ‘str’. One
special property of the search function is that, when a user searches for a contact from the contact list
then suggestions (Contacts with prefix as the string entered so for) are shown after user enters each
character.
Note : Contacts in the list consist of only lower case alphabets.

Phone Directory can be efficiently implemented using Trie Data Structure. We insert all the contacts into
Trie.

Generally search query on a Trie is to determine whether the string is present or not in the trie, but in this
case we are asked to find all the strings with each prefix of ‘str’. This is equivalent to doing a DFS
traversal on a graph. From a Trie node, visit adjacent Trie nodes and do this recursively until there are no
more adjacent. This recursive function will take 2 arguments one as Trie Node which points to the
current Trie Node being visited and other as the string which stores the string found so far with prefix as
‘str’.

107
Each Trie Node stores a boolean variable ‘isLast’ which is true if the node represents end of a
contact(word).

User will enter the string character by character and we need to display suggestions with the prefix
formed after every entered character.
So one approach to find the prefix starting with the string formed is to check if the prefix exists in the
Trie, if yes then call the displayContacts() function. In this approach after every entered character we
check if the string exists in the Trie.
Instead of checking again and again, we can maintain a pointer prevNode‘ that points to the TrieNode
which corresponds to the last entered character by the user, now we need to check the child node for the
‘prevNode’ when user enters another character to check if it exists in the Trie. If the new prefix is not in
the Trie, then all the string which are formed by entering characters after ‘prefix’ can’t be found in Trie
too. So we break the loop that is being used to generate prefixes one by one and print “No Result
Found” for all remaining characters.

PROGRAM:

// C++ Program to Implement a Phone


// Directory Using Trie Data Structure
#include <bits/stdc++.h>
using namespace std;

struct TrieNode
{
// Each Trie Node contains a Map 'child'
// where each alphabet points to a Trie
// Node.
// We can also use a fixed size array of
// size 256.
unordered_map<char,TrieNode*> child;

// 'isLast' is true if the node represents


// end of a contact
bool isLast;

// Default Constructor
TrieNode()
{
// Initialize all the Trie nodes with NULL
for (char i = 'a'; i <= 'z'; i++)
child[i] = NULL;

isLast = false;
}
};

108
// Making root NULL for ease so that it doesn't
// have to be passed to all functions.
TrieNode *root = NULL;

// Insert a Contact into the Trie


void insert(string s)
{
int len = s.length();

// 'itr' is used to iterate the Trie Nodes


TrieNode *itr = root;
for (int i = 0; i < len; i++)
{
// Check if the s[i] is already present in
// Trie
TrieNode *nextNode = itr->child[s[i]];
if (nextNode == NULL)
{
// If not found then create a new TrieNode
nextNode = new TrieNode();

// Insert into the Map


itr->child[s[i]] = nextNode;
}

// Move the iterator('itr') ,to point to next


// Trie Node
itr = nextNode;

// If its the last character of the string 's'


// then mark 'isLast' as true
if (i == len - 1)
itr->isLast = true;
}
}

// This function simply displays all dictionary words


// going through current node. String 'prefix'
// represents string corresponding to the path from
// root to curNode.
void displayContactsUtil(TrieNode *curNode, string prefix)
{
// Check if the string 'prefix' ends at this Node
// If yes then display the string found so far
if (curNode->isLast)
cout << prefix << endl;
109
// Find all the adjacent Nodes to the current
// Node and then call the function recursively
// This is similar to performing DFS on a graph
for (char i = 'a'; i <= 'z'; i++)
{
TrieNode *nextNode = curNode->child[i];
if (nextNode != NULL)
displayContactsUtil(nextNode, prefix + (char)i);
}
}

// Display suggestions after every character enter by


// the user for a given query string 'str'
void displayContacts(string str)
{
TrieNode *prevNode = root;

string prefix = "";


int len = str.length();

// Display the contact List for string formed


// after entering every character
int i;
for (i=0; i<len; i++)
{
// 'prefix' stores the string formed so far
prefix += (char)str[i];

// Get the last character entered


char lastChar = prefix[i];

// Find the Node corresponding to the last


// character of 'prefix' which is pointed by
// prevNode of the Trie
TrieNode *curNode = prevNode->child[lastChar];

// If nothing found, then break the loop as


// no more prefixes are going to be present.
if (curNode == NULL)
{
cout << "nNo Results Found for "" << prefix
<< "" n";
i++;
break;
}
110
// If present in trie then display all
// the contacts with given prefix.
cout << "nSuggestions based on "" << prefix
<< "" are n";
displayContactsUtil(curNode, prefix);

// Change prevNode for next prefix


prevNode = curNode;
}

// Once search fails for a prefix, we print


// "Not Results Found" for all remaining
// characters of current query string "str".
for (; i<len; i++)
{
prefix += (char)str[i];
cout << "nNo Results Found for "" << prefix
<< "" n";
}
}

// Insert all the Contacts into the Trie


void insertIntoTrie(string contacts[],int n)
{
// Initialize root Node
root = new TrieNode();

// Insert each contact into the trie


for (int i = 0; i < n; i++)
insert(contacts[i]);
}

// Driver program to test above functions


int main()
{
// Contact list of the User
string contacts[] = {"gforgeeks" , "geeksquiz"};

// Size of the Contact List


int n = sizeof(contacts)/sizeof(string);

// Insert all the Contacts into Trie


insertIntoTrie(contacts, n);

string query = "gekk";


111
// Note that the user will enter 'g' then 'e', so
// first display all the strings with prefix as 'g'
// and then all the strings with prefix as 'ge'
displayContacts(query);

return 0;
}

OUTPUT:
Suggestions based on "g" are
geeksquiz
gforgeeks
Suggestions based on "ge" are
geeksquiz
No Results Found for "gek"
No Results Found for "gekk"

112

Potrebbero piacerti anche