Module 2

Download as pdf or txt
Download as pdf or txt
You are on page 1of 29

MODULE –2

QUEUES: Queues, Circular Queues, Using Dynamic Arrays, Multiple Stacks


and queues.
LINKED LISTS : Singly Linked, Lists and Chains, Representing Chains in C,
Linked Stacks and Queues, Polynomials

QUEUES ABSTRACT DATA TYPE


DEFINITION
• “A queue is an ordered list in which insertions (additions, pushes) and deletions (removals and
pops) take place at different ends.”
• The end at which new elements are added is called the rear, and that from which old elements
are deleted is called the front.
• Given a queue Q = (a0, a1,……… an-1) , a0, is the front element an-1 is the rear element, ai+1 is
behind ai 0< =i < n-1.
If the elements are inserted A, B, C, D and E in this order, then A is the first element deleted from
the queue. Since the first element inserted into a queue is the first element removed,queues are
also known as First-In-First-Out (FIFO) lists.
QUEUE REPRESENTATION USING ARRAY
• Queues may be represented by one-way lists or linear arrays.
• Queues will be maintained by a linear array QUEUE and two pointer variables: FRONT-
containing the location of the front element of the queue
• REAR-containing the location of the rear element of the queue.
• The condition FRONT = NULL ie front==-1will indicate that the queue is empty
• Figure indicates the way elements will be deleted from the queue and the way new elements will
be added to the queue.
• Whenever an element is deleted from the queue, the value of FRONT is increased by 1; this can
be implemented by the assignment FRONT := FRONT + 1
• When an element is added to the queue, the value of REAR is increased by 1; this can be
implemented by the assignment REAR := REAR + 1
Different types of queues are:
1.Linear queue(ordinary queue)
2.Circular queue
3.Double ended queue(dequeue)
4.Priority queue
Implementation of the queue operations as follows.
1. Queue Create
Queue CreateQ(maxQueueSize) ::=
#define MAX_QUEUE_SIZE 100 /* maximum queue size */
typedef struct
{
int key;
/* other fields */
} element;
element queue[MAX_QUEUE_SIZE];
int rear = -1;
int front = -1;
2. Boolean IsEmptyQ(queue) ::= front =-1 OR front >rear
3. Boolean IsFullQ(queue) ::= rear == MAX_QUEUE_SIZE-1
In the queue, two variables are used which are front and rear. The queue increments rear in addq( )
and front in delete( ). The function calls would be addq (item); and item =delete( );
4. addq(item)
Program: Add to a queue
void addq(int *rear, element item,int*front,int queue[])
{
// add an item to the queue
if (*rear == MAX_QUEUE_SIZE-1)
{ queue_Full();
return;
}
if(*front==-1)
{
(*front)++;
(*rear)++;
}
else
{
(*rear)++;
}
queue [*rear] = item;
}
5. deleteq( )
Program: Delete from a queue
element deleteq(int *front, int *rear,int queue[])
{ /* remove element at the front of the queue */
if( (*front == -1)||(*front>*rear))
return queue_Empty( ); /* return an error key
else{
delete_item=queue[*front];
(*front)++;
return delete_item;
}
6. queueFull( ) and queue_Empty()
The queueFull function which prints an error message and terminates execution
void queueFull()
{
fprintf(stderr, "Queue is full, cannot add element");
exit(EXIT_FAILURE);
}
void queue_Empty()
{
fprintf(stderr, "Queue is Empty");
exit(EXIT_FAILURE);
}
7.Display the queue
void display()
{
if( (*front == -1)||(*front>*rear))
return queue_Empty( );
else
{
for(i=front;i<=rear;i++)
{ printf(“%d”,q[i]);
}
}
Application of queues
Example: Job scheduling
• Queues are frequently used in creation of a job queue by an operating system. If the operating
system does not use priorities, then the jobs are processed in the order they enter the system.
• Figure illustrates how an operating system process jobs using a sequential representation for its
queue

Drawback of Queue
When item enters and deleted from the queue, the queue gradually shifts to the right as shown in
figure.

In this above situation, when we try to insert another item, which shows that the queue is full .
This means that the rear index equals to MAX_QUEUE_SIZE -1. But even if the space is available
at the front end, rear insertion cannot be done.
Overcome of Drawback using different methods
Method 1
• When an item is deleted from the queue, move the entire queue to the left so that the first element
is again at queue[0] and front is at -1. It should also recalculate rear so that it is correctly positioned.
• Shifting an array is very time-consuming when there are many elements in queue & queueFull
has worst case complexity of O(MAX_QUEUE_SIZE)

Method 2:
Circular Queue
• It is “The queue which wrap around the end of the array.” The array positions are arranged in a
circle.
• In this convention the variable front is changed. front variable points one position
counterclockwise from the location of the front element in the queue. The convention for rear is
unchanged.
CIRCULAR QUEUES
• It is “The queue which wrap around the end of the array.” The array positions are arranged in a
circle as shown in figure.
Implementation of Circular Queue Operations
• When the array is viewed as a circle, each array position has a next and a previous position. The
position next to MAX-QUEUE-SIZE -1 is 0, and the position that precedes 0 is MAX-QUEUE-
SIZE -1.
• When the queue rear is at MAX_QUEUE_SIZE-1, the next element is inserted at position 0.
• In circular queue, the variables front and rear are moved from their current position to the next
position in clockwise direction. This may be done using code
if (rear = = MAX_QUEUE_SIZE-1)
rear = 0;
else rear++;
Addition & Deletion
• To add an element, increment rear one position clockwise and insert at the new position. Here
the MAX_QUEUE_SIZE is 8 and if all 8 elements are added into queue and that can be represented
in below figure (a).
• To delete an element, increment front one position clockwise. The element A is deleted from
queue and if we perform 6 deletions from the queue of Figure (b) in this fashion, then queue
becomes empty .
• If the element I is added into the queue as in figure (c), then rear needs to increment by 1 and the
value of rear is 8. Since queue is circular, the next position should be 0 instead of 8. This can be
done by using the modulus operator, which computes remainders.
Program: Add to a circular queue
void addq(element item)
{
if(front==(rear+1)% MAX_QUEUE_SIZE)
printf(“queue is full”);
else
{
if((front==-1)&&(rear==-1))
{
front++;
rear++ ;
queue [rear] = item;
}
else{
rear = (rear +1) % MAX_QUEUE_SIZE;
queue [rear] = item;
}
}
Program: Delete from a circular queue
element deleteq()
{
if((front==-1)&&(rear==-1))
return queueEmpty( ); /* return an error key */
else
{
item=queue[front];
if(front==rear)
{
front=rear=-1;
}
else
front = (front+1)% MAX_QUEUE_SIZE;
return item;
}
Circular Queue using Dynamic Arrays
To insert an element into a circular queue using dynamic array- Assume q is pointer to an integer,
two index variables front and rear are initialized to 0 and -1 respectively. Another variable count
is initialized to 0 which indicate queue is empty. Initial size of the queue denoted by SIZE is 1.
Design: Before inserting, we check whether sufficient space is available in the circular queue. We
know that if count value is same as SIZE, then circular queue is full. The code for this condition
can be written as shown below:
if (front=(rear+1)%maxsize)
{
printf(“Q full:\n”);
return;
}
But, once the queue is full, instead of returning the control, we can increase the size of array using
realloc() function and the above code can be modified as shown below:
if (front=(rear+1)%maxsize )
{
printf(“Q Full: update size, insert item\n ”);maxsize++;
q = (int *) realloc(q, maxsize*sizeof(int) );
MULTILPLE STACKS AND QUEUES
• In multiple stacks, we examine only sequential mappings of stacks into an array. The array is one
dimensional which is memory[MEMORY_SIZE]. Assume n stacks are needed, and then divide
the available memory into n segments. The array is divided in proportion if the expected sizes of
the various stacks are known. Otherwise, divide the memory into equal segments.
• Assume that i refers to the stack number of one of the n stacks. To establish this stack, create
indices for both the bottom and top positions of this stack. boundary[i] points to the position
immediately to the left of the bottom element of stack i, top[i] points to the top element. Stack i is
empty iff boundary[i]=top[i]

Implementation of the add operation


void push(int i, element item)
{ /* add an item to the ith stack */
if (top[i] == boundary[i+l])
stackFull(i);
else
{
top[i++];
s[top[i]]=item;
}
}
Implementation of the delete operation
element pop(int i)
{ /* remove top element from the ith stack */
if(top[i] == boundary[i])
printf(“Stack is empty”);
else
{
item=s[top[i]];
top[i--];
}
}
The top[i] == boundary[i+1] condition in push implies only that a particular stack ran out
of memory, not that the entire memory is full. But still there may be a lot of unused space
between other stacks in array memory as shown in Figure.
Therefore, create an error recovery function called stackFull , which determines if there is
any free space in memory. If there is space available, it should shift the stacks so that space
is allocated to the full stack.
LINKED LIST
DEFINITION
A linked list, or one-way list, is a linear collection of data elements, called nodes, where the linear
order is given by means of pointers. That is, each node is divided into two parts:
• The first part contains the information of the element, and
• The second part, called the link field or nextpointer field, contains the address of the next node
in the list.
A linked list is a dynamic data structure where each element (called a node) is made up of two
items - the data and a reference (or pointer) which points to the next node. A linked list is a
collection of nodes where each node is connected to the next node through a pointer.

In the above figure each node is pictured with two parts.

➢ The left part represents the information part of the node, which may contain an entire

record of data items.

➢ The right part represents the link field of the node

➢ An arrow drawn from a node to the next node in the list.

➢ The pointer of the last node contains a special value, called the NULL.

A pointer variable called first which contains the address of the first node. A special case is the list
that has no nodes; such a list is called the null list or empty list and is denoted by the null pointer
in the variable first.
Types of linked List:
1Singly linked list

2.Doubly linked list


3.Circular singly linked list

4.Circular Doubly linked list

REPRESENTATION OF LINKED LISTS IN MEMORY


Let LIST be a linked list. Then LIST will be maintained in memory as follows.
1. LIST requires two linear arrays such as DATA and LINK-such that DATA[K] and LINK[K]
contains the information part and the nextpointer field of a node of LIST.
2. LIST also requires a variable name such as START which contains the location of the beginning
of the list, and a nextpointer sentinel denoted by NULL-which indicates the end of the list.
3. The subscripts of the arrays DATA and LINK will be positive, so choose NULL = 0, unless
otherwise stated.
The following examples of linked lists indicate that the nodes of a list need not occupy adjacent
elements in the arrays DATA and LINK, and that more than one list may be maintained in the
same linear arrays DATA and LINK. However, each list must have its own pointer variable giving
the location of its first node
Linked List Operations(Representing Chains in C)
1. Create
Initially we make ‘first’ as ‘NULL’ . When we create a new node, name it as ‘temp’ and store the
value in its data field. For example, enter 10 to linked list as in Fig.1. Now connect the new node
to ‘first’ as in Fig1. Now make ‘temp’ as ‘first’ so that we can connect next new node to ‘first’
directly as in Fig. We can create ‘n’ number of nodes in the same way.

Program code for create operation


struct node
{
int data;
struct node *link;
};
struct node*first=NULL,*temp,*last;
2.Insert to Front
It works same as create function, by inserting new node to front. Here only one node can
be inserted at a time.
Program code for insert front operation
void insert_front()
{
temp = (struct node *) malloc(sizeof (struct node));
printf("Enter the data to be inserted:\n");
scanf("%d",temp->data);
temp->link=NULL;
}
if(first==NULL)
first=temp;
else
{
temp->link=FIRST;
FIRST=temp;
}
3.Insert to End
Suppose we have empty list, then first is equal to NULL. Then directly create new node and make
it as first. But suppose we have list . Now if we want to perform insert end, then new node to be
attached to right side of the last node (right of 10 here). Create a new node and name it as temp
and read new data(30) to temp . Check if last-->link=NULL and if it is not equal to NULL make
last=last-->link and last-->link=NULL and then connect new node ‘temp’ to ‘last->link’

Program code for insert end operation


void insert_end()
{
last=first;
temp = (struct node *) malloc(sizeof (struct node));
printf("Enter the data to be inserted:\n");
scanf("%d",temp->data);
temp->link=NULL;
if(first==NULL)
first=temp;
else
{
while(last->link!=NULL)
{
last=last->link;
}
last->link=temp;
}
}
4.Delete from Front
Suppose if we want to delete a node from front , (delete node contains data 20), then make ‘temp’
as ‘first’ and delete temp->data and make ‘temp->link’ as ‘first’. If first=NULL, then that means
there is no element in the list.
Program code for delete front operation
void delete_front()
{
temp = first;
if(first == NULL)
printf(“\n list is empty”);
else
{
printf(“deleted element is %d”,temp->data);
first=first->link;
free(temp);
}
}
5.Delete from End
Suppose if we want to delete a node from the end delete node contains data 30. If first=NULL,
that means there is no element in the list. Otherwise make ‘temp’ as ‘first’ . Then check if
temp->link= NULL, if it is not equal to NULL, then make next node as temp and Once again check
if temp->link=NULL, if not, repeat the same previous operation until temp->link=NULL . When
temp->link=NULL, delete temp->data and make last->link to point to NULL
Program code for delete end operation
void delete_end()
{
last=NULL;
temp=first;
if(first==NULL) // Check for empty list
printf("List is empty\n");
else if(first->link==NULL) // // Check for single node in SLL
{
printf("Deleted element is %d\n",temp->data);
free(first);
first=NULL;
}
else
{
while(temp->link!=NULL)
{
last=temp;
temp=temp->link;
}
last->link=NULL;
printf("Deleted element is %d\n",temp->data);
free(temp); // delete last node
}
return;
}
6.Traverse (Display) the linked list
Suppose if ‘first’ is equal to NULL, then no need of traversing. Directly display that list is empty.
Otherwise we need to traverse the whole list by traversing node by node. For that make ‘first’ as
‘temp’ and start traversing from first and display the traversed node data i.e.
temp->data. Then make next node as temp for traversing next node and so on until we reach
NULL. If we want to count the number of nodes, then put the counter. Initially set the count value
to one and increment the count value after traversing each node.
Program code for traverse operation
void display_count()
{
temp=first;
while(temp->link!=NULL)
{
printf(“%d\t”,temp->data);
temp=temp->link;
}
printf(“%d\t”,temp->data);
}
LINKED STACKS AND QUEUES
The below figure shows stacks and queues using linked list. Nodes can easily add or delete a node
from the top of the stack. Nodes can easily add a node to the rear of the queue and add or delete a
node at the front.
Linked Stacks(insertion at front,deletion at front)

• We have seen how a stack is created using an array. This technique of creating a stack is
easy,but the drawback is that the array must be declared to have some fixed size.
• In case the stack is a very small one or its maximum size is known in advance, then
• the array implementation of the stack gives an efficient implementation.
• But if the array size cannot be determined in advance, then the other alternative, i.e., linked
representation, is used. The linked representation of a stack is shown in Fig.3.9.1

• The push operation is used to insert an element into the stack. The new element is added at
the topmost position of the stack. Consider the linked stack shown in Fig. 3.9.2(a). To insert
an element with value 9, we first check if TOP=NULL. If this is the case, then we allocate
memory for a new node, store the value in its DATA part and NULL in its NEXT part. The
new node will then be called TOP. However, if TOP! =NULL, then we insert the new node
at the beginning of the linked stack and name this new node as TOP. Thus, the updated
stack becomes as shown in Fig. 3.9.2(b).
• The pop operation is used to delete the topmost element from a stack. However,
before deleting the value, we must first check if TOP=NULL, because if this is the case, then it
means that the stack is empty and no more deletions can be done. If an attempt is made to delete a
value from a stack that is already empty, an UNDERFLOW message is printed. Consider the stack
shown in Fig. 3.9.4 (a). In case TOP! =NULL, then we will delete the node pointed by TOP, and
make TOP point to the second element of the linked stack. Thus, the updated stack becomes as
shown in Fig. 3.9.4 (b).
Linked Queue(insertion at end ,deletion at front)

• When the array implementation of the queue gives an efficient implementation. But if the
array size cannot be determined in advance, the other alternative ,i.e.the linked
representation is used.
• In a linked queue, every element has two parts, one that stores the data and another which
holds the address of the next element. The START pointer of the linked list is used as
FRONT. Here we will also use another pointer called REAR, which will store the address
of the last element in the queue. All insertions will be done at the rear end and all the
deletions will be done at front end. If FRONT=REAR=NULL, then it indicates that the
queue is empty. The linked representation of queue is shown in Fig. 3.10.1.

• The insert operation is used to insert an element into the queue. The new element is added
as the last element of the queue. Consider the linked queue shown in Fig. 3.10.2 (a). To
insert an element with value 9, we first check if FRONT=NULL. If this is the case, then
we allocate memory for a new node, store the value in its DATA part and NULL in its
NEXT part. The new node will then be called FRONT and REAR. However, if FRONT!
=NULL, then we insert the new node at the rear end of the linked queue and name this new
node as REAR. Thus, the updated queue becomes as shown in Fig. 3.10.2(b).
Deletion:

• The delete operation is used to delete the element that is first inserted
• The delete operation is used to delete the element that is first inserted into the queue. i.e.
the element whose address is stored at FRONT.
• However, before deleting the value, we must first check if FRONT=NULL, because if this
is the case, then it means that the queue is empty and no more deletions can be done. If an
attempt is made to delete a value from a stack that is already empty, an UNDERFLOW
message is printed.
• Consider the stack shown in Fig. 3.10.4(a). To delete an element, we first check if
FRONT=NULL. If it is false, then we delete the 1st node pointed by the FRONT. The
FRONT will now point to the 2nd element of the linked queue. Thus the updated queue
becomes as shown in Fig. 3.10.4(b).
Element deleteq(int i)
{
queuePointer temp=front[i];
eement item;
if(!temp)
return queueEmpty();
item=temp->data;
front[i]=temp->link;
free(temp);
return(item);
}

Applications of Linked lists: Polynomials


Linked lists can be used to represent polynomials and the different operations that can be
performed on them. A polynomial is a combination of coefficients and exponents. We
represent a polynomial, each term as a node containing coefficients and exponent field, as
well as a pointer to next term.

Polynomial representation
Let us see how a polynomial is represented in the memory using a linked list. Consider a
polynomial 6x3 + 9x2 + 7x + 1. Every individual term in a polynomial consists of two
parts, a coefficient and a power. Here, 6, 9, 7, and 1 are the coefficients of the terms that
have 3, 2, 1, and 0 as their powers respectively. Every term of a polynomial can be
represented as a node of the linked list. Figure 3.11.1 shows the linked representation of
the terms of the above polynomial.

Polynomial Addition
Consider an example polynomial shown in Fig. 3.11.2. To add polynomial, we
examine their terms starting at the nodes pointed by a and b. There are three cases:
Program Code for polynomial addition for singly linked list
polyptr addpoly (polyptr a, polyptr b) {
{ if(a->link)
polyptr c, *temp; {
c->link=(struct c->exp=a->exp;
poly*)malloc(sizeof(struct c->coef=a->coef;
poly)); a=a->link;
c=c->link; }
c->link = NULL; if(b->link)
while( a->link && b->link) {
{ c->exp=b->exp;
if( a->exp>b->exp) c->coef=b->coef;
{ b=b->link;
c->exp=a->exp; }
c->coef=a->coef; c->link= (struct poly*)malloc
a=a->link; (sizeof(struct poly));
} c=c->link;
else if( a->exp<b->exp) c->link = NULL;
{ }
c->exp=b->exp;
c->coef=b->coef;
b=b->link;
}
else
{
c->exp=a->exp;
c->coef=a->coef + b->coef;
a=a->link;
b=b->link;
}
c->link=(struct
poly*)malloc(sizeof(struct
poly));
c=c->link;
c->link = NULL;
while (a->link || b->link)
Circular list representation of Polynomial

The zero polynomial is represented as in Fig. 3.12 (a);while a(x) = 3x 14+2x8+1 can be
represented as in Fig 3.12 (b). here link field of last node points to the 1st node in the list. So
we call this a circular linked list. To simplify the addition algorithm for polynomial
represented as circular linked list, we set coef and exp field of header node to -1. The
structure can be written as in Fig. 3.12 (c).
polyptr addpoly (polyptr a, polyptr b) {
{ if(a->link)
polyptr c, *temp; {
c->link=(struct poly*)malloc(sizeof(struct c->exp=a->exp;
poly)); c->coef=a->coef;
c=c->link; a=a->link;
temp=c; }
c->link = NULL; if(b->link)
while( a->link && b->link) {
{ c->exp=b->exp;
if( a->exp>b->exp) c->coef=b->coef;
{ b=b->link;
c->exp=a->exp; }
c->coef=a->coef; c->link= (struct poly*)malloc
a=a->link; (sizeof(struct poly));
} c=c->link;
else if( a->exp<b->exp) c->link = NULL;
{ }
c->exp=b->exp; c->link=temp;
c->coef=b->coef;
b=b->link;
}
else
{
c->exp=a->exp;
c->coef=a->coef + b->coef;
a=a->link;
b=b->link;
}
c->link=(struct poly*)malloc(sizeof(struct
poly));
c=c->link;
c->link = NULL;
while (a->link || b->link)

Program Code for polynomial addition for circular singly linked list

You might also like