Professional Documents
Culture Documents
Dr Mourad Raafat
Motivation: Why Queue? First In First Out (FIFO)
• In a queue,
– new values are always added at the rear of the list
– values are removed from the opposite end of the list, the
front
Input D C B A Output
• Examples of queues
– checkout at supermarket
– Toll Station
• Car comes, pays, leaves
– Check-out in Big super market
• Customer comes, checks out and leaves
– More examples: Printer, Office Hours, …
© Waleed A. Yousef 2008 2
E.g., Printing Queue
n-1 3 2 1 0
D C B A
After A leaves,
n-1 3 2 1 0
D C B
n-1 3 2 1 0
D C B A
Max_Size
rear front
…
Fr
ar
on
Re
t
Occupied
Circular Queue
Max-1
0 Front Rear
2
… Occupied …
Unwinding
Front Rear
Occupied
0 1 … …
Max-1
Linear
© Waleed A. Yousef 2008
Implementation 7
Checking the Boundary conditions
Rear and Front advance in this direction
0 MAX-1
Queue with two elements
F R
F R
Full Condition:
Next to Rear = Front
Therefore we waste one location R F 8
© Waleed A. Yousef 2008
Better solution: Use indicator variable to
distinguish between Empty and Full conditions.
Rear and Front advance in this direction
Empty queue:
Next to Rear = Front.
Size=0 R F
R F
Full queue:
Next to Rear = Front.
Size=MAX R F
9
Again: Definitions, where every thing should start from!
11
User Level
typedef struct queue{ (interface)
int front;
int rear; void main(){
int size;
QueueEntry entry[MAXQUEUE]; Queue q;
}Queue;
front
rear
size
entry
12
void CreateQueue(Queue *pq){ User Level
pq->front= 0; (interface)
pq->rear = -1;
void main(){
pq->size = 0;
}
//Initializing front =5 and rear Queue q;
=4 will work if MAXQUEUE >=6. But,
since MAXQUEUE can be 1 we CreateQueue(&q);
intialize as above.
MAXQUEUE-1
}
front
&q
rear pq
size
0
entry
13
void Append(QueueEntry e, Queue* pq){
pq->rear = (pq->rear + 1) % MAXQUEUE;
pq->entry[pq->rear] = e;
pq->size++;
}
MAXQUEUE-1
front
&q
pq rear
size
0
© Waleed A. Yousef 2008
entry 14
void Serve(QueueEntry *pe, Queue* pq){
*pe = pq->entry[pq->front];
pq->front = (pq->front + 1) % MAXQUEUE;
pq->size--;
}
MAXQUEUE-1
front
&q
pq rear
&e size
pe
0
© Waleed A. Yousef 2008
entry 15
int QueueEmpty(Queue* pq){
return !pq->size;
}
MAXQUEUE-1
front
rear
size
0
© Waleed A. Yousef 2008
entry 16
int QueueSize(Queue* pq){
return pq->size;
}
void ClearQueue(Queue* pq){
pq->front = 0;
pq->rear = -1;
pq->size = 0;
}//same as CreateQueue. No nodes to free.
MAXQUEUE-1
front
rear
size
0
© Waleed A. Yousef 2008
entry 17
void TraverseQueue(Queue* pq, void (*pf)(QueueEntry)){
int pos, s;
for(pos=pq->front, s=0; s<pq->size; s++){
(*pf)(pq->entry[pos]);
pos=(pos+1)%MAXQUEUE;
}
}
MAXQUEUE-1
front
rear
size
0
© Waleed A. Yousef 2008
entry 18
Linked Queues(to overcome fixed size limitations):
Just get the idea now, do not worry about details.
q.rear q.front q.rear q.front
Node
q
Empty Queue Queue of size 1
pn
New
node
Last in
q.rear q.Front
pn
20
Type Definition
New
node
}
CreateQueue
&q
pq
q
22
void Append(QueueEntry e, Queue* pq){
QueueNode*pn=(QueueNode*)malloc(sizeof(QueueNode));
pn->next=NULL;
pn->entry=e;
User Call:
Queue q;
QueueEntry e;
pq->rear->next=pn;
pq->rear=pn; Append(e, &q);
e
pq->size++; pn
}
&q
e
pq
23
Always take care of special cases (queue is empty)
void Append(QueueEntry e, Queue* pq){
QueueNode*pn=(QueueNode*)malloc(sizeof(QueueNode));
pn->next=NULL;
pn->entry=e;
if (!pq->rear)
pq->front=pn;
else
pq->rear->next=pn;//run time error for empty queue
pq->rear=pn;
pq->size++;
}
&q pn
pq
e
Last in
pq->size--;
}
&q
pq pn
&q
pq pn
q 27
© Waleed A. Yousef 2008
void ClearQueue(Queue* pq){
while(pq->front){
pq->rear=pq->front->next;
free(pq->front);
pq->front=pq->rear;
}
pq->size = 0;
}/*Moving with two pointers,
Exactly as in LinkedStacks*/ Last in
&q
pq
© Waleed A. Yousef 2008 28
void TraverseQueue(Queue* pq, void(*pf)(QueueEntry)){
for(QueueNode *pn=pq->front; pn; pn=pn->next)
(*pf)(pn->entry);
}
Last in
&q
pq
pn
© Waleed A. Yousef 2008 29
Very important note for all linked structures. E.g., in Queues:
In Push and Append we have to check for exhausted memory.
The code can be modified to:
• Important notice:
– if we keep adding and removing from the first position (the
head of the list) the general list will behave as a stack.
• Application:
– In queues, sometimes we need a priority for some elements.
We may need to put an emergency call prior to others.
#include "Global.h"
p +1
p
0
size entry
© Waleed A. Yousef 2008 42
0 size-1 MAXLIST-1
size head
0 1 p … size-1
size head
© Waleed A. Yousef 2008 45
void DestroyList(List *pl){
ListNode *q;
while(pl->head){
q=pl->head->next;
free(pl->head);
pl->head=q;
}
pl->size=0;
}//we took it before many times: // (n)
0 1 p … size-1
size head
© Waleed A. Yousef 2008 46
void InsertList(int pos, ListEntry e, List *pl){
size
ListNode *p, *q;
int i; head
p=(ListNode *)malloc(sizeof(ListNode));
p->entry=e;
0
p->next=NULL;
…
} 1
pl->size++;
} // (n) but without shifting elements.
size-1
…
}
pl->size++;
return 1;
} size-1
else return 0;
}
© Waleed A. Yousef 2008 49
void DeleteList(int pos, ListEntry *pe, List *pl){ size
int i; head
ListNode *q, *tmp;
0
if (pos==0){
*pe=pl->head->entry;
tmp=pl->head->next;
free(pl->head); 1
pl->head=tmp;
}// it works also for one node tmp
else{ pos-1
for(q=pl->head, i=0; i<pos-1; i++)
q=q->next; q
pos
*pe=q->next->entry;
tmp=q->next->next;
free(q->next);
pos+1
q->next=tmp;
}// check for pos=size-1 (tmp will be NULL)
tmp
pl->size--;
} //O(n) but without shifting elements. size-1
head
size-1
Array-based Linked
CreateList (1) (1)
InsertList (n) (n)
DeleteList (n) (n)
RetrieveList (1) (n)
ReplaceList (1) (n)
Many applications processes the entries in order, i.e., moving from one
entry to the next.
k 0 1 k size-1
currentpos current size head
© Waleed A. Yousef 2008 53
Design Enhancement: Learn how you modify your design to
enhance the performance
k 0 1 k size-1
currentpos current size head
© Waleed A. Yousef 2008 54
void InsertList(int pos, ListEntry e, List *pl){
ListNode *p; 0
p=(ListNode *)malloc(sizeof(ListNode));
p->entry=e;
cu pos
t
en
p->next=NULL;
t
rr
en
if (pos==0){ currentpos
rr
p->next=pl->head;
cu
pl->head=p;
pl->currentpos=0; //new pos-1
pl->current=pl->head; //new pl->current
}
else{//pl->current is used in place of q previously.
if (pos<=pl->currentpos){ pos
pl->currentpos=0;//as i=0
pl->current=pl->head;//as q=pl->head
} //new.
…
for(; pl->currentpos!=pos-1; pl->currentpos++)
pl->current=pl->current->next; p
p->next=pl->current->next;
pl->current->next=p; size-1
}
pl->size++;
© Waleed A. Yousef 2008 55
void DeleteList(int pos, ListEntry *pe, List *pl){
ListNode *tmp; 0
if (pos==0){
*pe=pl->head->entry;
cu pos
t
en
pl->current=pl->head->next;
t
rr
en
free(pl->head); currentpos
rr
pl->head=pl->current; //new
cu
pl->currentpos=0; //new
} pos-1
else{ pl->current
if (pos<=pl->currentpos){
pl->currentpos=0;
pl->current=pl->head; pos
tmp
}
for(; pl->currentpos!=pos-1; pl->currentpos++)
pl->current=pl->current->next;
…
*pe=pl->current->next->entry;
tmp=pl->current->next->next;
free(pl->current->next);
pl->current->next=tmp; size-1
}
pl->size--;
© Waleed A. Yousef 2008 56
You have to modify ReplaceList and RetrieveList in
the same manner. (Do it as a homework). Check also for other
functions, e.g., CreateList (for initialization)
Having this function may simplify the code for the case of
having current and currentpos.
Read the code from the book and solve the review problems
k 0 1 k size-1
currentpos current size
© Waleed A. Yousef 2008 58