Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
REGULATION – GR17
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
Additional Experiments
2
ADVANCED DATA STRUCTURE LABORATORY
INDEX SHEET
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
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
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
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:
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
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
26
The traversal method use to achieve Array representation is Level Order
PROGRAM:
#include <stdio.h>
int array[100], n;
main()
while(1)
printf("4.Quit \n");
scanf("%d", &choice);
switch(choice)
case 1:
insert(num, n);
n = n + 1;
break;
case 2:
scanf("%d", &num);
delete(num);
break;
case 3:
display();
break;
case 4:
exit(0);
default:
}/*End of switch */
}/*End of while */
}/*End of main()*/
display()
int i;
28
if (n == 0)
return;
printf("\n");
}/*End of display()*/
int 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)
if (num == array[i])
break;
if (num != array[i])
return;
n = n - 1;
insert(array[i], i);
return;
30
right = 2 * i + 2; /* right child of i*/
return;
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*/
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
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.
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
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
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
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
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.
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
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
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:
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
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:
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
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).
73
T1 T2 T3 T4
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>
/* 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);
}
// 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);
}
OUTPUT:
Preorder traversal of the modified Splay tree is 20 50 30 40 100 200
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;
struct Node
{
int data;
bool color;
Node *left, *right, *parent;
// Constructor
Node(int data)
{
this->data = data;
left = right = parent = NULL;
}
};
inorderHelper(root->left);
cout << root->data << " ";
inorderHelper(root->right);
}
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);
}
}
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
pt->parent->right = pt_right;
pt_right->left = pt;
pt->parent = pt_right;
}
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
pt->parent->right = pt_left;
pt_left->right = pt;
pt->parent = pt_left;
}
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)
{
/* 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;
}
// 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);
return 0;
}
OUTPUT:
Inoder Traversal of Created Tree
1 2 3 4 5 6 7
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
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>
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
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
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>
graph->edge =
(struct Edge*) malloc( graph->E * sizeof( struct Edge ) );
return graph;
90
}
if (x == y)
return 1;
Union(parent, x, y);
}
return 0;
}
if (isCycle(graph))
printf( "graph contains cycle" );
else
printf( "graph doesn't contain cycle" );
return 0;
}
OUTPUT:
graph contains cycle
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.
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 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);
// Construct a tree from the merged array and return root of the tree
return sortedArrayToBST (mergedArr, 0, m+n-1);
}
return(node);
}
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++;
}
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;
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;
return root;
}
getchar();
return 0;
}
OUTPUT:
Following is Inorder traversal of the merged tree
20 40 50 70 80 100 120 300
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;
};
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);
return current;
}
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)
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[].
PROGRAM:
102
void constructLowerArray (int *arr[], int *countSmaller, int n)
{
int i, j;
printf("\n");
}
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;
// Trie Node.
struct trieNode
{
struct trieNode *child[MAX];
int freq; // To store frequency
};
// Base case
if (root->freq == 1)
{
prefix[ind] = '\0';
cout << prefix << " ";
return;
}
// 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
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:
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;
// 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;
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