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

Programming Assignment II

The document describes the implementation of queue data structures using a cursor-based linked list data structure. It includes functions to initialize the list, allocate new nodes, enqueue and dequeue elements, find the rear and front of the queue, and print the contents. The key functions are: 1. MakeNull() initializes all nodes by setting elements and next pointers to -1. 2. CursorAlloc() finds and returns the position of an empty node for insertion. 3. Enqueue() inserts an element at the rear by calling CursorAlloc() and updating pointers. 4. Dequeue() removes the front element by updating the header and freeing the node. 5. Rear() and PrevList

Uploaded by

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

Programming Assignment II

The document describes the implementation of queue data structures using a cursor-based linked list data structure. It includes functions to initialize the list, allocate new nodes, enqueue and dequeue elements, find the rear and front of the queue, and print the contents. The key functions are: 1. MakeNull() initializes all nodes by setting elements and next pointers to -1. 2. CursorAlloc() finds and returns the position of an empty node for insertion. 3. Enqueue() inserts an element at the rear by calling CursorAlloc() and updating pointers. 4. Dequeue() removes the front element by updating the header and freeing the node. 5. Rear() and PrevList

Uploaded by

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

PROGRAMMING PROJECT-II

DATA STRUCTURE AND DBMS (AV 482)


Question
As part of Programming Project-II of AV 482, you are required to implement
Queue ADTs based on Cursor-based List data structure. You are required to
also create a simple application program that can create two queues using a
single Cursor-based list.
The application program shall use the Queue ADT to Enque, Deque, and
Front procedures. Further, the application program shall include a function to
print the contents of each queue. For example, after a creating a single or
multiple queues, I should be able to Enque a small set of data items for one
or more queues and printout the contents of the queues.

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

//SpaceSize is the maximum array size including both queues


#define SpaceSize 256

//definition and declaration of the element and queue items


typedef int PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;
typedef int elementtype;

//each node in queue has a data element and a next pointer


struct Node
{
elementtype Elements;
Position Next;

};
struct Node CursorSpace[SpaceSize];

//initializing queue headers, which may be changed during insertion


List L1=1,L2=2;
int count1=0,count2=0,checklist=0;

//initialize element and next pointer


void MakeNull();
//allocate empty node for insertion
Position CursorAlloc(List Q);
//enqueue to the rear of queue
void Enqueue(elementtype x,List Q);
//deinitialize element and next pointer
void CursorFree(List Q);
//dequeue from the front of queue
void Dequeue(List Q);
//return next pointer of rear node
Position Rear(List Q);
//return node position of rear node of queue
Position PrevList(List Q);
//print elements of queue in FIFO order
void Print(List Q);
//print node position and element of front node
void Front(List Q);
//print the entire cursor based array
void PrintArray();

Function 1: MakeNull()
Explanation

This function is used to initialize the element of each node to -1 as a default


value
The Positon next which is used as a next pointer to the node is also initialized
to -1
This is because no node can have an index of -1(or any negative number) so
this indicates completely empty node

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

A position P is set to 1, which is initially the first unused node position

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

The CursorAlloc() function is called to return the position of an empty node at


the end of queue
Depending on whether it is the first or the second queue, the respective
element counters are incremented
It might happen that because of subsequent insertions in one queue, the
previously initialized header position for the other queue may get occupied
In such a case, the header location has to be incremented till an immediate
unused slot is reached
For example, if the first header is 1 and the second header is 2, but two
insertions is done in the first queue before any insertion in the second queue,
the position 2 gets filled with an element of the first queue. Then the header
for the second queue has to be moved to slot 3 or after, which is still an
empty node
If there are elements present in any of the queue, the PrevList() function is
called for respective queues to obtain the position of the rear node. The next
pointer of this rear node is set to an empty node.
The 0th node's next pointer is also set to the same empty node because it
stores the position of the immediate empty node. This assignment is
essential because sometimes, during alternate insertions in either queue, the
next pointer of the previous queue may point to an invalid position.
For example, if the first queue , with header 1, has an element at node 1
and next pointer 2, and the second queue has a header at 2, insertion in the
second queue will result in an element at node 2, and the next pointer at 3 or
any other empty node.
This turns the next pointer of the first queue invalid since it is pointing to an
element of the second queue. Thus, the next pointer has to be made to point
to the next empty node, which is 3 in this case. Now, both the first and
second queue's rear elements point to an empty node.

void Enqueue(elementtype x,List Q)


{
Position P,X;

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);
}

Function 10: PrintArray()


Explanation

Prints the entire Cursor based Array with slot number, elements, and next
pointer, in order

void PrintArray()
{
int i;

printf("Cursor Array List\n");


for(i=0;i<SpaceSize;i++)
printf("%d %d %d\n",i,CursorSpace[i].Elements,CursorSpace[i].Next);
printf("\n");
}

Function 11: main()


Explanation

To start execution of program, with choice of queue, operations on individual


queue and error checks
Two condition checks, with if-else clause, is required, one for each queue, due
to unavailability of reference by pointer, so the actual queue header L1 or L2
respectively for first or second queue have to be passed during each
operation function call

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;

default: printf("No matching option found\n");


break;
}
}
else if(chq==2)
{
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-1-count2-count1);
scanf("%d",&totele);
if(totele>SpaceSize-1-count2-count1)
{

printf("Exceeds queue size\n");


break;
}
for(i=1;i<=totele;i++)
{
printf("Enter the element to Enqueue:");
scanf("%d",&x);
Enqueue(x,L2);
}
break;
case 2:
printf("Enter the number of elements to delete (<=%d) : ",count2);
scanf("%d",&totele);
if(totele>count2)
{
printf("Queue cannot have negative size\n");
break;
}
for(i=1;i<=totele;i++)
{
Dequeue(L2);
}
break;
case 3:
Print(L2);
break;
case 4: Front(L2);
break;
case 5: printf("Aborting\n");
exit(0);

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 1: Queue 1 has 3 elements Enqueued and printed

Figure 2: The Cursor List Array has been printed with elements and next positions

You might also like