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

Java Script

This document discusses stacks and queues, which are data structures that implement first-in, last-out (LIFO) and first-in, first-out (FIFO) operations respectively. Stacks are often used by compilers to store temporary information while queues are used in multiprocessing and network management to organize waiting jobs. The document then describes the abstract data type (ADT) operations, implementations, and examples of stacks and queues. It also introduces priority queues, which implement queue storage where each element has an associated priority value.

Uploaded by

fmsarwar
Copyright
© © All Rights Reserved
Available Formats
Download as RTF, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
44 views

Java Script

This document discusses stacks and queues, which are data structures that implement first-in, last-out (LIFO) and first-in, first-out (FIFO) operations respectively. Stacks are often used by compilers to store temporary information while queues are used in multiprocessing and network management to organize waiting jobs. The document then describes the abstract data type (ADT) operations, implementations, and examples of stacks and queues. It also introduces priority queues, which implement queue storage where each element has an associated priority value.

Uploaded by

fmsarwar
Copyright
© © All Rights Reserved
Available Formats
Download as RTF, PDF, TXT or read online on Scribd
You are on page 1/ 8

Stacks and Queues

Various types of dynamic storage are employed by system and applications software. For
example, a compiler frequently uses stacks to store information that is retrieved soon after it is
stored. Multiprocess computing and network management software often employs queues for
managing waiting and executing jobs (programs submitted by users).

Stack ADT

Concept: A stack implements a last-in, first-out (LIFO) buffer.

Definition: A stack is a list where insertion and deletion operations are performed only at the
head of the list.

Observation. A stack can be thought of like the spring-loaded stacks of plates in a cafeteria. You
put a plate (data object) on top of the stack, and all you can see is the top plate. When you
remove a plate from the stack, you still see the top plate only, unless the stack is empty.

ADT Operations: The following ADT operations are pertinent to stacks:

Size - returns the number of objects on (currently stored in) the stack, an integer.

IsFull,IsEmpty - returns true if the stack is full (size equals some maximum constraint), or empty
(size equals zero), respectively.

Push - adds an object to the top of the stack if the stack is not full.
Pop - removes an object from the top of the stack if the stack is not empty.

Peek or Top - returns a copy of the object on top of the stack if the stack is not empty.

Example: Let a stack S begin as empty, then let us push 1 onto the stack. This is shown in Step 1
of Figure 2.4.1. Next, we push the values 2 and 3 onto the stack, as shown in Steps 2 and 3. If S
has capacity n = 3, then S is full. Popping the values off the stack as shown in Steps 4-6 yields size
= 0 (empty stack). Note how the values that were first pushed onto the stack come off the top of
the stack last. That is why the stack is called a LIFO buffer.

Figure 2.4.1. Stack operations that push a sequence (1,2,3) onto a stack, then pop it off to yield
output (3,2,1).

Implementation
A stack is usually implemented with a list, but can be implemented with an array. The list
implementation was previously described at a high level. Note that push and pop operations are
implemented at the head of the list. Additionally, the implementation should maintain a counter
for the list size that is incremented when a push operation is executed and decremented when a
pop operation is executed. A peek operation simply copies the value at the head of the list. This
can be implemented with pop, copy, and push operations.

The array implementation of a stack is more interesting, and can be faster on many different
types of machines. The array implementation has a counter called a stack pointer that denotes
the position of the array where a value was last inserted. Assuming that the array a is one-
dimensional and has indices ranging from 1 to some large value N, let the stackpointer be
denoted by j. This means that the last push() operation stored value a[j].

If another push operation is specified, then we need to perform the following steps:

1. Check to see if i = N. If so, the stack is full and we cannot execute push() and must notify
the user of stack overflow.

2. If j < N, then increment j and store the value v in push(v) as a[j] = v.

In contrast, if a pop operation is specified, then we need to perform the following steps:

3. Check to see if j > 0. If not, the stack is empty and we cannot execute pop() and must
notify the user of stack underflow.

4. If j > 0, then decrement j and return the value v at a[j].

5. As an optional step, store a sentinel value that indicates a null value in a[j]. This is useful
in case the stackpointer is lost, corrupted, or destroyed.

The peek operation is implemented as return(a[1]).


Figure 2.4.2. Stack operations when a stack is implemented in terms of an array.

Queue ADT

Concept: A queue implements a first-in, first-out (FIFO) buffer.

Definition: A queue is a list where insertion (deletion) is performed only at the tail (head) of the
list.
Observation. A queue can be thought of like the line of customers in the bank or post office.
When a customer arrives in the queue, that person is added to back (tail) of the queue. When
the clerk calls for the next customer to be served, that person exits the queue at the front of the
queue.

ADT Operations: The following ADT operations are pertinent to queues:

Size - returns the number of objects in the queue, which is an integer.

IsFull,IsEmpty - returns true if the queue is full (size equals some maximum constraint), or empty
(size equals zero), respectively.

Enqueue - adds an object to the rear of the queue if the queue is not full.

Dequeue - removes an object from the front of the queue if the queue is not empty.

Front - returns a copy of the object at the front of a nonempty queue.

Example: Let a queue Q store the elements 1, 2, and 3, where 1 is at the front of the queue.
This is shown in Figure 2.4.3, Steps 1-3, below. If Q has finite capacity, then we can detect that Q
is full. Dequeueing of the values 1, 2, and 3 is shown in Figure 2.4.3, Steps 4-6, which yields an
empty queue. Note how the values that were first enqueued come out the front of the queue
first. That is why a queue implements a FIFO buffer.
Figu
re 2.4.3. Queue operations that enqueue each element of a sequence (1,2,3), then dequeue to
yield output (1,2,3).

Implementation: A queue is usually implemented with a list, since array implementations


are costly. For example, note that in Figure 2.4.3, Steps 4-6, the contents of the queue would
have to be shifted up one location at each dequeueing operation. Alternatively, one could use
front and rear pointers to denote the limits of the queue, but the contents would periodically
have to be shifted, so that the front of the queue would be able to accept data. This clearly
requires O(n) work for an n-element queue. Hence, array implementations of queues are not
customary.

We next examine a special type of queue, called a priority queue, which allows us to perform
special types of operations, among them sorting of values in the queue.

Sorting with Priority Queues


Let us assume that we have a queue with the special property that the smallest value in the
queue is always at the front of the queue. Don't worry just yet about how that would be
implemented; let's simply assume that property exists. Given such a queue, sorting the
sequence of numbers stored in the queue would be easy, if we wanted to sort in ascending
order. For example, for the i-th of n entries in the queue, we would delete the front of the
queue, and put it in the i-th position in the sorted output.

Special types of queues like this exist, and they are called priority queues. We discuss this
concept in detail, as follows.

Concept: A priority queue implements queue-based storage of objects, where each object is
associated with a priority value. The higher priorities indicate objects that have greater
operational importance.

Definition: A priority queue is a queue, where each element of the queue stores a tuple
containing a value x and a priority p(x) that is an integer.

Application: Priority queues are often used in scheduling applications, where a given job or
work order is assigned a priority. For example, if "1" denotes the highest priority, then one would
want to perform the highest priority jobs first (the elements of the queue where p(x) is smallest).

Figure 2.5.1. Priority queue that stores {(B,3), (A,1), (C,4), (D,2)}, where the second element of
each tuple denotes the priority, with 1 being the highest priority.

Implementation: Priority queues are usually implemented using the heap data structure
(discussed below). The heap ADT operation of MIN (or MAX) allows one to find the minimum- or
maximum-valued element stored in a heap that stores n data, in O(log n) time. Thus, if the MIN
or MAX operation acts on the priority value, then one could (in the previous discussion of
applications) retrieve the smallest priority value, which would be associated with the heap (or
priority queue) element storing a pointer to the highest-priority job.
Various instances of priority queue are used in communications (e.g., network traffic
management), operations research (e.g., assembly line optimization), and job scheduling (e.g.,
for a multiprocessor computing machine), among other applications. Thus, priority queues are of
practical importance.

You might also like