Java Software Structures - PowerPoint PPT Presentation

1 / 68
About This Presentation
Title:

Java Software Structures

Description:

Java Software Structures Lewis and Chase. 1. Chapter 8. Java Software Structures ... QueueADT.java Authors: Lewis/Chase // Defines the interface to a queue ... – PowerPoint PPT presentation

Number of Views:190
Avg rating:3.0/5.0
Slides: 69
Provided by: joec95
Category:

less

Transcript and Presenter's Notes

Title: Java Software Structures


1
Java Software Structures
  • Chapter 8 Queues

2
Chapter Objectives
  • Examine queue processing
  • Define a queue abstract data type
  • Demonstrate how a queue can be used to solve
    problems
  • Examine various queue implementations
  • Compare queue implementations

3
Queues
  • A queue is a linear collection whose elements are
    added on one end and removed from the other
  • First-In, First-Out (FIFO)
  • Elements are removed from a queue in the same
    order in which they are placed on the queue

4
Queues
5
Operations on a Queue
  • Enqueue - Adds an element to the rear of the
    queue.
  • Dequeue - Removes an element from the front of
    the queue.
  • First - Examines the element at the front of the
    queue.
  • isEmpty - Determines if the queue is empty.
  • Size - Determines the number of elements on the
    queue

6
Operations on a Queue
  • Sometimes enqueue is simply called add or insert
  • Dequeue is sometimes called remove or serve
  • The first operation is sometimes called front
  • Enqueue, dequeue, and first correspond to the
    stack operations push, pop, and peek
  • There are no operations that allow the user to
    reach into the middle of a queue

7
A Queue ADT
  • //
  • // QueueADT.java Authors Lewis/Chase
  • //
  • // Defines the interface to a queue collection.
  • //
  • package jss2
  • import java.util.Iterator
  • public interface QueueADT
  • // Adds one element to the rear of the queue
  • public void enqueue (Object element)
  • // Removes and returns the element at the
    front of the queue
  • public Object dequeue()
  • // Returns without removing the element at
    the front of the queue
  • public Object first()
  • // Returns true if the queue contains no
    elements
  • public boolean isEmpty()
  • // Returns the number of elements in the
    queue

8
A Queue ADT
9
Using Queues - Codes
  • A Caesar cipher is a simple approach to encoding
    messages by shifting each letter in a message
    along the alphabet by a constant amount k
  • Therefore, if k equals 3, the encoded message
  • vlpsolflwb iroorzv frpsohalwb
  • would be decoded into
  • simplicity follows complexity

10
Using Queues Codes
  • An improvement can be made to this encoding
    technique if we use a repeating key
  • Instead of shifting each character by a constant
    amount, we can shift each character by a
    different amount using a list of key values
  • For example, if the key values are
  • 3 1 7 4 2 5
  • then the first character is shifted by three, the
    second character by one, the third character by
    seven, etc

11
Using Queues - Codes
12
Using Queues - Codes
  • The program Codes.java uses a repeating key to
    encode and decode a message
  • The key of integer values is stored in a queue
  • After using a key value, it is put back on the
    end of the queue so that the key continually
    repeats as needed for long messages

13
Using Queues - Codes
  • Program Output
  • Encoded Message
  • Fxi(gvyludix,z\zqmvimqm?p(Xrnmit?gyrr\v
    mom?pyzv(Xgtp6
  • Decoded Message
  • All programmers are playwrights and all computers
    are lousy actors.

14
Using Queues - Codes
  • This program actually uses two copies of the key
    stored in two separate queues
  • The idea is that the person encoding the message
    has one copy of the key, and the person decoding
    the message has another
  • Also, note that this program doesnt bother to
    wrap around the end of the alphabet
  • Using a queue to store the key makes it easy to
    repeat the key by putting each key value back
    onto the queue as soon as it is used

15
Using Queues Ticket Counter
  • Consider the situation in which you are waiting
    in line to purchase tickets at a movie theatre
  • In general, the more cashiers there are, the
    faster the line moves
  • The theatre manager wants to keep his customers
    happy, but doesnt want to employ any more
    cashiers than he has to

16
Using Queues Ticket Counter
  • Our simulated ticket counter will use the
    following assumptions
  • There is only one line and it is first come first
    served (a queue),
  • Customers arrive on average every 15 seconds,
  • If there is a cashier available, processing
    begins immediately upon arrival,
  • Processing a customer request and getting them on
    their way takes on average 2 minutes (120
    seconds) from the time they reach a cashier.

17
Using Queues Ticket Counter
  • First we can create a Customer class
  • A Customer object keeps track of the time the
    customer arrives and the time the customer
    departs after purchasing a ticket
  • The total time spent by the customer is therefore
    the departure time minus the arrival time

18
Using Queues Ticket Counter
  • Our simulation will create a queue of customers,
    then see how long it takes to process those
    customers if there is only one cashier
  • Then well process the same queue of customers
    with two cashiers
  • Well continue this process for up to ten
    cashiers
  • At the end well compare the average time it
    takes to process a customer

19
Using Queues Ticket Counter
  • The program TicketCounter.java performs our
    simulation
  • The outer loop determines how many cashiers are
    used in each pass of the simulation
  • For each pass, the customers are taken from the
    queue in turn and processed by a cashier
  • The total elapsed time is tracked, and at the end
    of each pass the average time is computed

20
Using Queues Ticket Counter
  • Note that with eight cashiers, the customers do
    not wait at all
  • Increasing the number of cashiers to 9 or 10 or
    more will not improve the situation
  • Since the manager has decided he wants to keep
    the total average time to less than seven minutes
    (420 seconds), the simulation tells him that he
    should have six cashiers

21
Using Queues Radix Sort
  • Another interesting application of queues is the
    concept of a radix sort
  • Radix sort was not covered in Chapter 5 for two
    reasons.
  • First, radix sort is not a comparison sort and
    thus has very little in common with the
    techniques that we discussed in Chapter 5.
  • Second, to implement it effectively, a radix sort
    requires the use of a queue (several of them in
    fact) or similar collection

22
Using Queues Radix Sort
  • Recall that a sort is based on some particular
    value, called the sort key
  • A radix sort is based on the structure of the
    sort key
  • Separate queues are created for each possible
    value of each digit or character of the sort key
  • The number of queues, or the number of possible
    values, is called the radix
  • For example, if we were sorting strings made up
    of lowercase alphabetic characters, the radix
    would be 26

23
Using Queues Radix Sort
  • Lets look at an example that uses a radix sort
    to put ten three-digit numbers in order
  • To keep things manageable, well restrict the
    digits of these numbers to 0 though 5, which
    means well only need six queues
  • Each three-digit number to be sorted has a 1s
    position (right digit), a 10s position (middle
    digit), and a 100s position (left digit)

24
Using Queues Radix Sort
  • On the first pass, each number is put on the
    queue corresponding to its 1s digit
  • On the second pass, each number is put on the
    queue corresponding to its 10s digit
  • On the third pass, each number is put on the
    queue corresponding to its 100s digit

25
Using Queues Radix Sort
  • Originally, the numbers are loaded into the
    queues from the original list
  • On the second pass, the numbers are taken from
    the queues in a particular order
  • They are retrieved from the digit 0 queue first,
    and then the digit 1 queue, etc
  • Likewise, on the third pass, the numbers are
    again taken from the queues in the same way
  • When the numbers are pulled off of the queues
    after the third pass, they will be completely
    sorted

26
Using Queues Radix Sort
27
Using Queues Radix Sort
  • The program RadixSort.java implements the radix
    sort
  • For this example, we will sort four-digit
    numbers, and we wont restrict the digits used in
    those numbers
  • Using an array of ten queue objects (one for each
    digit 0 through 9), this method carries out the
    processing steps of a radix sort

28
Implementing Queues with Links
  • Since it is a linear data structure, we can
    implement a queue collection as a linked list of
    LinearNode objects, as we did with stacks
  • The primary difference is that we will have to
    operate on both ends of the list
  • Therefore, in addition to a reference pointing to
    the first element in list (called front), we will
    also keep track of a second reference that points
    to the rear element on the list (called rear).

29
Implementing Queues with Links
30
The Enqueue operation
  • The enqueue operation requires that we put the
    new element on the rear of the list
  • In the general case, that means setting the next
    reference of the current last element to the new
    one, and resetting the rear reference to the new
    last element
  • However, if the queue is currently empty, the
    front reference must also be set to the new (and
    only) element

31
The Enqueue operation
//---------------------------------------------
-------------------- // Adds the specified
element to the rear of the queue.
//------------------------------------------------
----------------- public void enqueue (Object
element) LinearNode node new
LinearNode(element) if (isEmpty())
front node else rear.setNext
(node) rear node count
32
The Enqueue operation
33
The Dequeue operation
  • The first issue to address when implementing the
    dequeue operation is to ensure that there is at
    least one element to return
  • If not, an EmptyCollectionException is thrown
  • If there is at least one element in the queue,
    the first one in the list is returned and the
    front reference is updated

34
The Dequeue operation
//---------------------------------------------
-------------------- // Removes the element
at the front of the queue and returns a //
reference to it. Throws an EmptyCollectionExceptio
n if the // queue is empty.
//------------------------------------------------
----------------- public Object dequeue()
throws EmptyCollectionException if
(isEmpty()) throw new EmptyCollectionExce
ption ("queue") Object result
front.getElement() front
front.getNext() count-- if
(isEmpty()) rear null return
result
35
The Dequeue operation
36
Other operations
  • The remaining operations in the linked queue
    implementation are fairly straightforward and are
    similar to how they were handled for the stack
    and bag collections
  • These operations are left as programming projects

37
Implementing Queues with Arrays
  • One array-based strategy for implementing a queue
    is to fix one end of queue (say, the front) at
    index 0 of the array
  • The elements are then stored contiguously in the
    array

38
Implementing Queues with Arrays
39
The Enqueue operation
  • The enqueue operation adds a new element to the
    rear of the queue
  • As long as there is room in the array to for an
    additional element, it can be stored in the
    location indicated by the integer rear
  • The technique for expanding the capacity of the
    queue array is the same as the one used for other
    collections

40
The Enqueue operation
//---------------------------------------------
-------------------- // Adds the specified
element to the rear of the queue, expanding //
the capacity of the queue array if necessary.
//------------------------------------------------
----------------- public void enqueue (Object
element) if (size() queue.length)
expandCapacity() queuerear
element rear
41
The Enqueue operation
42
The Dequeue operation
  • the dequeue operation must assure that after
    removing the first element of the queue, the new
    first element (currently the second element in
    the list) is stored at index 0 of the array
  • because we store the elements contiguously, we
    cannot have gaps in the list
  • Therefore all elements must be shifted down one
    cell in the array

43
The Dequeue operation
  • //------------------------------------------------
    -----------------
  • // Removes the element at the front of the
    queue and returns a
  • // reference to it. Throws an
    EmptyCollectionException if the
  • // queue is empty.
  • //---------------------------------------------
    --------------------
  • public Object dequeue() throws
    EmptyCollectionException
  • if (isEmpty())
  • throw new EmptyCollectionException
    ("queue")
  • Object result queue0
  • // shift the elements
  • for (int scan0 scan
  • queuescan queuescan1
  • rear--
  • queuerear null
  • return result

44
The Dequeue operation
45
Other operations
  • The implementation of the first, isEmpty, size,
    iterator, and toString operations using this
    strategy are left as programming projects

46
Implementing Queues with Circular Arrays
  • The main problem with the array-based strategy
    discussed in the previous section is that the
    front end of the queue is fixed at index 0
  • Therefore, every time a dequeue operation is
    performed, all elements stored in the queue array
    had to be shifted
  • If the queue is large, or if many dequeue
    operations are performed, this creates a lot of
    time-consuming shift operations.

47
Implementing Queues with Circular Arrays
  • Fixing the rear of the queue at index 0 does not
    solve the problem
  • That change would simply require the element
    shifting to occur in the enqueue method (before
    the element is added) rather than in the dequeue
    method (after the element is removed)

48
Implementing Queues with Circular Arrays
  • The key is not to fix either end
  • As elements are dequeued, the front of the queue
    will move further into the array
  • As elements are enqueued, the rear of the queue
    will also move further into the array
  • The challenge comes when the rear of the queue
    reaches the end of the array
  • Enlarging the array at this point is not a
    practical solution, and does not make use of the
    now empty space in the lower indexes of the array

49
Implementing Queues with Circular Arrays
  • To make this solution work, we will use a
    circular array to implement the queue
  • A circular array is not a new construct it is
    just a way to think about the array used to store
    the collection
  • Conceptually, the array is used as a circle,
    whose last index is followed by the first index

50
Implementing Queues with Circular Arrays
51
Implementing Queues with Circular Arrays
  • Two integer values are used to represent the
    front and rear of the queue
  • The value of front represents the location where
    the first element in the queue is stored
  • The value of rear represents the next available
    slot in the array (not where the last element is
    stored)

52
Implementing Queues with Circular Arrays
  • The value of rear no longer represents the number
    of elements in the queue
  • We will use a separate integer value to keep a
    count of the elements
  • When the rear of the queue reaches the end of the
    list, it wraps around to the front of the array

53
Implementing Queues with Circular Arrays
54
(No Transcript)
55
Implementing Queues with Circular Arrays
  • In general, after an element is enqueued, the
    value of rear is incremented
  • But when an enqueue operation fills the last cell
    of the array (at the largest index), the value of
    rear must be set to 0
  • Likewise, after an element is dequeued, the value
    of front is incremented
  • After removing the element at the largest index,
    the value of front must be set to 0 instead of
    being incremented

56
Implementing Queues with Circular Arrays
  • The appropriate update to the values of rear and
    front can be accomplished in one calculation
    using the remainder operator ()
  • Therefore, if queue is the name of the array
    storing the queue, the following line of code
    will update the value of rear appropriately
  • rear (rear1) queue.length

57
Implementing Queues with Circular Arrays
  • All of the operations for the circular array
    implementation of a queue are left as exercises.

58
Analysis of Queue Implementations
  • There is a space complexity difference between
    the algorithms
  • The linked implementation requires more space per
    node since it has to store both the object and
    the link to the next object
  • However, it only allocates space as it needs it
    and then can store as many elements as needed up
    to the limitations of the hardware
  • The array implementation does not require the
    additional space per element for the pointer
  • However, typically array implementations allocate
    more space than is required and thus may be
    wasteful

59
Analysis of Queue Implementations - Enqueue
  • The enqueue operation for the linked
    implementation consists of the following steps
  • create a new node with the element pointer
    pointing to the object to be added to the queue
    and with the next pointer set to null,
  • set the next pointer of the current node at the
    rear of the queue to point to the new object,
  • set the rear pointer to point to the new object,
    and
  • increment the count of elements in the queue.

60
Analysis of Queue Implementations - Enqueue
  • Each of these steps is O(1) and thus the
    operation is O(1)
  • The analysis of the array implementation and the
    circular array implementation also results in O(1)

61
Analysis of Queue Implementations Dequeue
  • The dequeue operation for the linked
    implementation consists of the following steps
  • check to make sure the queue is not empty (throw
    an exception if it is),
  • set a temporary pointer equal to the element
    pointed to by the element pointer of the node
    pointed to by the front pointer,
  • set the front pointer equal to the next pointer
    of the node at the head of the queue,
  • decrement the count of elements in the queue, and
  • return the element pointed to by the temporary
    pointer.

62
Analysis of Queue Implementations Dequeue
  • As with our previous examples, each of these
    operations consists of a single comparison or a
    simple assignment and is therefore O(1).
  • Thus the dequeue operation for the linked
    implementation is O(1)

63
Analysis of Queue Implementations Dequeue
  • The dequeue operation for the non-circular array
    implementation consists of the following steps
  • Check to make sure the queue is not empty (throw
    an exception if it is),
  • Set a temporary object equal to the first element
    in the array,
  • Shift all of the elements in the array one
    position to the left,
  • Decrement the rear and the count, and
  • Return the temporary object.

64
Analysis of Queue Implementations Dequeue
  • All of these steps are O(1) with the exception of
    shifting all of the remaining elements in the
    array to the left which is O(n)
  • Thus the dequeue operation for the non-circular
    array implementation has time complexity O(n)

65
Analysis of Queue Implementations Dequeue
  • The dequeue operation for the circular array
    implementation consists of the following steps
  • Check to make sure the queue is not empty (throw
    an exception if it is),
  • Set a temporary object equal to the object in the
    front of the queue,
  • Set position front of the array to null,
  • Decrement the count, and
  • Return the temporary object.
  • All of these steps are O(1) resulting in the
    dequeue operation for the circular array
    implementation being O(1).

66
Analysis of Queue Implementations Other
Operation
  • The front, isEmpty, and size operations are all
    O(1)

67
Summary of Key Concepts
  • Queue elements are processed in a FIFO manner
    the first element in is the first element out.
  • A queue is a convenient collection for storing a
    repeating code key.
  • Simulations are often implemented using queues to
    represent waiting lines.
  • A radix sort is inherently based on queue
    processing.
  • A linked implementation of a queue is facilitated
    by references to the first and last elements of
    the linked list.

68
Summary of Key Concepts
  • The enqueue and dequeue operations work on
    opposite ends of the collection.
  • Because queue operations modify both ends of the
    collection, fixing one end at index 0 requires
    that elements be shifted.
  • Treating arrays as circular eliminates the need
    to shift elements in an array queue
    implementation.
  • The shifting of elements in a non-circular array
    implementation creates an O(n) complexity.
Write a Comment
User Comments (0)
About PowerShow.com