Queues: A First-In-First-Out Data Structure, Slides of Algorithms and Programming

An overview of queues as a data structure, their basic operations, and various applications. Queues are a first-in-first-out (fifo) or first-come-first-served (fcfs) structure, where items can only be removed from the front and added to the back. I/o buffers, scheduling queues, cpu scheduling, and array-based implementations.

Typology: Slides

2012/2013

Uploaded on 04/27/2013

netii
netii 🇮🇳

4.4

(7)

91 documents

1 / 23

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Queues
Defn. As a data structure, a queue is an ordered collection of data
items with the property that items can be removed only at one
end, called the front of the queue, and items can be added only at
the other end, called the back of the queue. Basic operations are:
construct: Create an empty queue
empty: Check if a queue is empty
addQ: Add a value at the back of the queue
front: Retrieve the value at the front of the queue
removeQ: Remove the value at the front of the queue
Whereas a stack is a Last-In-First-Out (LIFO) structure, a queue is a
First-In-First-Out (FIFO) or First-Come-First-Served (FCFS)
structure.
Queue:
Front: Remove ONLY
Back: Add ONLY
Docsity.com
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17

Partial preview of the text

Download Queues: A First-In-First-Out Data Structure and more Slides Algorithms and Programming in PDF only on Docsity!

Queues

Defn. As a data structure, a queue is an ordered collection of data

items with the property that items can be removed only at one

end, called the front of the queue, and items can be added only at

the other end, called the back of the queue. Basic operations are:

construct: Create an empty queue

empty: Check if a queue is empty

addQ: Add a value at the back of the queue

front: Retrieve the value at the front of the queue

removeQ: Remove the value at the front of the queue

Whereas a stack is a Last-In-First-Out (LIFO) structure, a queue is a

First-In-First-Out ( FIFO ) or First-Come-First-Served ( FCFS )

structure.

Queue :

Front: Remove ONLY

Back: Add ONLY

Docsity.com

a. I/O buffers: queues, scrolls, deques

♦ From a file: ( queue )

Infile >> X;

X

Input

Buffer

CPU

Disk Memory

Input Buffer

queues input for

the CPU

Examples:

Scroll :

Front: Remove

or

Add

Back: Add

or

Remove

Screen handling: ( deque — double-

ended queue)

♦ Printer queue: When files are submitted to a printer, they are

placed in the printer queue. The printer software executes

an algorithm something like:

for (;;)

while (printerQueue.empty())

sleep 1;

printFile = printerQueue.removeQ();

Print(printFile);

b. Scheduling queues in a multi-user

computer system:

Probably uses a priority

queue : Items with lower

priority are behind all those

with higher priority.

(Usually a new item is

inserted behind those with the

same priority.)

c. CPU Scheduling:

Queues vs. Stacks

  • Stacks are a LIFO container
    • Store data in the reverse of order received
  • Queues are a FIFO container
    • Store data in the order received
  • Stacks then suggest applications where some sort of reversal

or unwinding is desired.

  • Queues suggest applications where service is to be rendered

relative to order received.

  • Stacks and Queues can be used in conjunction to compare

different orderings of the same data set.

  • From an ordering perspective, then, Queues are the “opposite”

of stacks

  • Easy solution to the palindrome problem

Array Implementation

Any implementation of a queue requires: storage for the data as well as markers (“pointers”) for the front and for the back of the queue.

An array-based implementation would need structures like myArray, an array to store the elements of the queue myFront, an index to track the front queue element myBack, an index to track the position following last queue element

Additions to the queue would result in incrementing myBack. Deletions from the queue would result in incrementing myFront. Clearly, we’d run out of space soon!

Solutions include: Shifting the elements downward with each deletion (YUCK!!) Viewing array as a circular buffer, i.e. wrapping the end to the front

“Circular” Array-Implementation

Wraparound keeps the addition/deletion cycle from walking off the edge of the storage array.

Say, myArray has QUEUE_CAPACITY elements.

When myBack hits the end of myArray, a deletion should wrap myBack around to the first element of myArray, viz:

myBack++; if (myBack = = QUEUE_CAPACITY) myBack = 0;

//equivalently (preferred, concise) myBack = (myBack + 1) % QUEUE_CAPACITY;

Analogous handling of myFront needed.

QUEUE class

#ifndef QUEUE #define QUEUE const int QUEUE_CAPACITY = 128; typedef int QueueElement; class Queue { /***** Function Members *****/ public: Queue(); bool empty() const; bool full() const; void addQ(const QueueElement & value); QueueElement front const(); //nondestructive “peek” void removeQ(); /***** Data Members *****/ private: QueueElement myArray[QUEUE_CAPACITY]; int myFront, myBack; }; // end of class declaration #endif

QUEUE class implementation

Queue::Queue() { myFront = myBack = 0; }

bool Queue::empty() { return myFront == myBack; }

bool Queue::full() { return myFront == (myBack + 1) % QUEUE_CAPACITY; }

Linked list implementation

Linked list implementation is another approach for queue representation.

The interface to the class Queue empty, addq, removeq, front, etc. would not change

The storage structure would be a linked list. The markers would be pointers now rather than indices into an array. myFront would contain the address of the first node in this list myBack would contain the address of the last node in this list

empty would test if myFront was a nonnull pointer, addq would allocate a new node, link it off myBack and update myBack, removeq would remove the first element and update myFront, front would return a copy of the element whose address was in myFront

Deque

A deque (double-ended queue) is similar to a queue BUT additions and deletions may be performed on either end.

Hence, an implementation needs a directive (tag) indicating at what end the operation is to be performed OR multiple methods should be provided.

We modify a queue's circular array implementation here.

#include using namespace std;

enum where {front, rear};

/* Deque implemented with same data members myArray myFront myBack Constructors and empty(), full() methods the same */ Docsity.com

Deque enqueuing

//better to provide two addition methods void Deque::push_front(int item) {if ((myBack +1)% QUEUE_CAPACITY == myFront) cout << "FULL, cannot add to queue." << endl; else // enqueue at front { if (!myFront) myFront = QUEUE_CAPACITY; else myFront--; myArray[myFront] = item; } return; } void Deque::push_back(int item) { if ((myBack +1)% QUEUE_CAPACITY == myFront) cout << "FULL, cannot add to queue." << endl; else // regular enqueuing { myArray[myBack] = item; myBack = (myBack+ 1) % QUEUE_CAPACITY; } return; }

Deque dequeuing

int Deque::pop_front() // assume non-empty { int item = myArray[myFront]; myFront= (myFront+ 1) % QUEUE_CAPACITY; return item; }

void Deque::pop_back() // assume non-empty { if (!myBack) myBack = QUEUE_CAPACITY; else myBack--; int item = myArray[myBack]; // dequeue from rear return item; }