Programming Assignment II
Programming Assignment II
Source Code
#include<stdio.h>
#include<stdlib.h>
};
struct Node CursorSpace[SpaceSize];
Function 1: MakeNull()
Explanation
Process Flow
A loop is run from 1 to the SpaceSize, which is maximum length of the array.
The element and next of the cursor array is set to -1
void MakeNull()
{
int i;
for(i=0;i<SpaceSize;i++)
{
CursorSpace[i].Elements=-1;
CursorSpace[i].Next=-1;
}
}
Function 2: CursorAlloc()
Explanation
This function assigns the node position as well as the next pointer of an
immediate unused slot
Slots with lower index are higher in precedence and likely to get assigned
earlier
The 0th node is kept as an unallocated slot only for indicating the position of
the next empty node
Process Flow
Call the function Rear() to find the next pointer of the rear node of the queue,
the node position corresponding to this rear pointer will be the position where
insertion has to be carried out
If the checklist, which is an indicator of whether queue is full is not -1 i.e.
queue is not yet full, a loop from P till an empty node is reached is run to find
an empty node position
The 0th node's next element, which stores position of next empty node is set
to the empty node position found
If the queue is exactly full, then the 0th node's next element will store the
maximum limit of array SpaceSize. If this is the case, set checklist to -1 as an
indicator of queue full
Return the node position viable for the insertion operation
Position CursorAlloc(List Q)
{
Position P,R;
P=1;
if(checklist!=-1)
{
R=Rear(Q);
for(;P<SpaceSize;P++)
{
if(CursorSpace[P].Next==-1)
{
break;
}
}
CursorSpace[0].Next=P;
}
else
exit(0);
if(P==SpaceSize)
{
printf("Queue Full. Aborting at next insertion.\n");
checklist=-1;
}
return R;
}
Function 3: Enqueue()
Process Flow
P=CursorAlloc(Q);
if(Q==L1)
count1++;
if(Q==L2)
count2++;
CursorSpace[P].Elements=x;
if(count1==1 && P!=L1 && Q==L1)
L1=P;
else if(count2==1 && P!=L2 && Q==L2)
L2=P;
if(count1!=0)
{
X=PrevList(L1);
CursorSpace[X].Next=CursorSpace[0].Next;
}
if(count2!=0)
{
X=PrevList(L2);
CursorSpace[X].Next=CursorSpace[0].Next;
}
}
Function 4:CursorFree()
Explanation
This function deinitializes the deleted node by setting the element and next
pointer to -1
Since the node is returned to the heap of empty array slots, this deallocated
node may be assigned again using CursorAlloc() function
void CursorFree(List Q)
{
Position P;
P=Q;
CursorSpace[P].Elements=-1;
CursorSpace[P].Next=-1;
}
Function 5: Dequeue()
Process Flow
A check is made for detecting which queue it is and whether the queue is
empty.
If the checklist, which is an indicator of queue being full is -1 i.e. queue is full,
the checklist is set to 0, indicating queue will have empty space for insertion
after deletion function is executed.
The PrevList() function is called to obtain the node position of the rear node,
and the next pointer of the rear node.
For a completely full queue, the next pointer points to an invalid location of
SpaceSize, so it is set to the newly deallocated position which is the same as
the header of the queue due to its FIFO nature.
This assignment is important otherwise the rear of the queue will continue to
indicate an invalid queue full even though there are empty spaces in the
queue due to dequeue operation.
The header of the queue is incremented to the node position indicated by its
next pointer, which is the next element in the queue. Thus the first element
of the queue is effectively dereferenced.
The count of elements in the queue is decremented by 1.
The CursorFree() function is called to deinitialize the element and next pointer
of the newly dequeued node.
void Dequeue(List Q)
{
Position P,X;
if(Q==L1 && count1>0)
{
if(checklist==-1)
{
checklist=0;
X=PrevList(L1);
CursorSpace[0].Next=CursorSpace[X].Next=L1;
}
L1=CursorSpace[L1].Next;
count1--;
CursorFree(Q);
}
else if(Q==L2 && count2>0)
{
if(checklist==-1)
{
checklist=0;
X=PrevList(L2);
CursorSpace[0].Next=CursorSpace[X].Next=L2;
}
L2=CursorSpace[L2].Next;
count2--;
CursorFree(Q);
}
else
printf("Queue Empty\n");
}
Function 6: Rear()
Process Flow
The queue is traversed starting from the header, till an empty node is
reached. This node is at the rear of the queue where the next insertion should
take place, and is returned from the function.
Initialization of next pointer of this empty node after the rear node to a value
different from -1 i.e. 0 to indicate an empty slot other than the typical empty
locations is esssential.
This is because when CursorAlloc will run a loop to search for an empty node,
this empty node, will come up as suitable and the CursorAlloc() function will
wrongly allocated the next pointer of rear to itself since this is currently also
an unallocated node.
For example, if queue 1 has an element at position 1 with next pointer 2,
Rear() will return 2, and CursorAlloc() search for empty node will also stop at
2 since this node is still empty at the time. Thus the next pointer of node 2
will be set to node 2 i.e. itself.
To avoid this, the next pointer of node 2, while returning from Rear() is
blocked as 0, so the CursorAlloc() search returns a different node as empty,
which can then be set as the next pointer of node 2, the current empty node
where insertion should occur.
Position Rear(List Q)
{
Position P;
P=Q;
while(CursorSpace[P].Next!=-1)
{
P=CursorSpace[P].Next;
}
CursorSpace[P].Next=0;
return P;
}
Function 7: PrevList()
Process Flow
This functions return the position of the rear node of the respective queues.
The counter is set to the number of elements in the corresponding queue
minus 1, so that the loop runs till the element before the rear element.
The next pointer of this element is the position of the rear node, which is then
returned.
Position PrevList(List Q)
{
int i;
Position P;
if(Q==L1)
i=count1;
else if(Q==L2)
i=count2;
P=Q;
i--;
while(i>0)
{
P=CursorSpace[P].Next;
i--;
}
return P;
}
Function 8: Print()
Explanation
This function prints out the elements of the queue in FIFO order, along with
the number of elements remaining in the queue
It makes use of the count of elements to run the loop from the header till the
rear of the queue is reached
void Print(List Q)
{
Position P,R;
P=Q;
int i;
if(Q==L1)
i=count1;
else
i=count2;
printf("##Number of elements: %d##\n",i);
while(i>0)
{
printf("%d ",CursorSpace[P].Elements);
P=CursorSpace[P].Next;
i--;
}
printf("\n");
}
Function 9: Front()
Explanation
This function prints the node position and element present in the front node
of the queue
The front node is the same as the header of the queue
void Front(List Q)
{
printf("The front of the queue is at slot %d with element
%d\n",Q,CursorSpace[Q].Elements);
}
Prints the entire Cursor based Array with slot number, elements, and next
pointer, in order
void PrintArray()
{
int i;
int main()
{
int i,cho,totele;
Position P;
List chq;
elementtype x;
MakeNull();
while(1)
{
printf("Choose a Queue or print Cursor Array\n1----Queue 1\n2----Queue
2\n3----Print Cursor Array\n");
scanf("%d",&chq);
if(chq==1)
{
printf("Choose an option\n1----Enqueue\n2----Dequeue\n3----Print\n4---Front\n5----Exit\n");
scanf("%d",&cho);
switch(cho)
{
case 1:
printf("Enter the number of elements to insert (<=%d) : ",SpaceSize-1count1-count2);
scanf("%d",&totele);
if(totele>SpaceSize-1-count1-count2)
{
printf("Exceeds queue size\n");
break;
}
for(i=1;i<=totele;i++)
{
printf("Enter the element to Enqueue:");
scanf("%d",&x);
Enqueue(x,L1);
}
break;
case 2:
printf("Enter the number of elements to delete (<=%d) : ",count1);
scanf("%d",&totele);
if(totele>count1)
{
printf("Queue cannot have negative size\n");
break;
}
for(i=1;i<=totele;i++)
{
Dequeue(L1);
}
break;
case 3:
Print(L1);
break;
case 4: Front(L1);
break;
case 5: printf("Aborting\n");
exit(0);
break;
break;
default: printf("No matching option found\n");
break;
}
}
else if(chq==3)
PrintArray();
else
printf("No such queue exists\n");
}
return 0;
}
Output
Figure 2: The Cursor List Array has been printed with elements and next positions