PRIORITY QUEUE CONCEPT

advertisement
PRIORITY QUEUE CONCEPT
A priority queue is best understood in comparison with a stack and a queue. To see this, imagine
a supermarket checkout, where customers, each with a certain number of items in the shopping
cart, arrive at the checkout counter:
ItemsInCart
6
12
4
9
15
7
Customer
Mary
//last to arrive
Joe
Jill
Pete
Stacy
Bev
//first to arrive
CHECKOUT COUNTER
Suppose also that the entries <6, Mary>, <12, Joe> … <7, Bev> are placed in a data container,
to reflect order of arrival, with <7, Bev> first in, <15, Stacy> next in, and so on, and <6, Mary>
in last.
If the cashier serves the customers in order of arrival, that is, <7, Bev> first and <6, Mary>last,
we have a conventional queue, i.e. First In, First Out, or FIFO.
If the cashier serves the customers starting with entries <6, Mary>, and ending with <7, Bev>,
we have a stack, i.e. Last In, First Out, or LIFO.
If the cashier serves the customers with entries in the order <4, Jill>, <6, Mary>, <7, Bev>, …
ending with <15, Stacy>, that is, service in order of lowest number of shopping items, we have
a priority queue, i.e. The entry inserted with the lowest priority key, no matter when inserted,
is the first entry out.
In this example, the first data item of each entry, the number of shopping items, serves as the
priority key.
Notice the technical term entry. A priority queue consists of a set of entries into the queue, each
entry consisting of a priority key and a value.
Applications
• Scheduling jobs on a workstation holds jobs to be performed and their priorities. When a
job is finished or interrupted, highest-priority job is chosen using Extract-Max. New jobs
can be added using Insert function.
• Operating System Design – resource allocation
• Data Compression -Huffman algorithm
• Discrete Event simulation
(1) Insertion of time-tagged events (time represents a priority of an event -- low time means
high priority)
(2) Removal of the event with the smallest time tag
18
Implementation
• Linked Lists
• Using a binary Heap – a special binary tree with heap property
We show Front and Rear arrows to provide a comparison with an ordinary queue, but they’re
not really necessary. The algorithms know that the front of the queue is always at the top of the
array at nItems-1, and they insert items in order, not at the rear. Figure below shows the
operation of the PriorityQ class methods.
Two items removed from front of priority queue
Key Comparison Method.
Normally the entry with the highest priority has the lowest priority key value, and is extracted
from the priority queue first.
That means that we need a way to compare the key values, so that we can say if the key of one
entry is greater or less than the key of another entry, and which key has the lowest value and
which the highest value.
The key comparison method may be very simple, based on integer values, as in the case of
number of shopping items above.
The Priority Queue ADT
A priority queue ADT will be implemented as a container of some kind that can support the
methods below.
constructor
Create a new, empty queue.
19
insert
Add a new item to the queue.
remove
Remove and return an item from the queue. The item that is returned is the one with the
highest priority.
empty
Check whether the queue is empty.
Sorting With a Priority Queue.
We can look at a priority queue as a black box. You can put entries into it, using insert(), in any
key order, take out a few entries, using removeMin(), put in some more and so on, as if using a
stack. But no matter how many we put in and take out, removeMin() always delivers the entry in
the queue with the lowest key value. This is obviously useful for sorting.
Suppose we want to sort a set of entries (each made up of a key and a value) in ascending order:
Step 1. Use insert() to insert, in any order, all the entries into the priority queue.
Step 2. Use removeMin() to extract the entries from the queue, and print them, or place them in
an array. The entries are now sorted.
Class PriorityQueue
The insert() method checks whether there are any items; if not, it inserts one at index 0.
Otherwise, it starts at the top of the array and shifts existing items upward until it finds the place
where the new item should go. Then it inserts the item and increments nItems. Note that if
there’s any chance the priority queue is full, you should check for this possibility with isFull()
before using insert().
The front and rear fields aren’t necessary as they were in the Queue class because, as we noted,
front is always at nItems-1 and rear is always at 0.
The remove() method is simplicity itself: It decrements nItems and returns the item from the
top of the array. The isEmpty() and isFull() methods check if nItems is 0 or maxSize,
respectively
public void insert(long item) // insert item
{
int j;
if(nItems==0)
// if no items,
queArray[nItems++] = item;
// insert at 0
else
// if items,
{
for(j=nItems-1; j>=0; j--)
// start at end,
{
if( item > queArray[j] )
// if new item larger,
queArray[j+1] = queArray[j]; // shift upward
else
// if smaller,
20
break;
// done shifting
} // end for
queArray[j+1] = item;
// insert it
nItems++;
} // end else (nItems > 0)
} // end insert()
//------------------------------------------------------------public long remove()
// remove minimum item
{ return queArray[--nItems]; }
Linked Lists
A linked list, in its simplest form, is a collection of nodes that together form a linear ordering.
Linked Lists are a very common way of storing arrays of data. The major benefit of linked lists is
that you do not specify a fixed size for your list. The more elements you add to the chain, the
bigger the chain gets.
There is more than one type of a linked list, we'll stick to singly linked lists (the simplest one).
If for example you want a doubly linked list instead, very few simple modifications will give
you what you're looking for. Many data structures (e.g. Stacks, Queues, Binary Trees) are often
implemented using the concept of linked lists. Some different types of linked lists are shown
below:
A few basic types of Linked Lists
Singly Linked List
Root node links one way through all the nodes. Last node links to null.
Circular Linked List
Circular linked lists have a reference to one node which is the tail node and all the nodes are
linked together in one direction forming a circle. The benefit of using circular lists is that
appending to the end can be done very guickly.
Doubly Linked List
Every node stores a reference to its previous node as well as its next. This is good if you need to
move back by a few nodes and don't want to run from the beginning of the list.
21
There's a diagram to help you realize the main disadvantage of arrays but not Linked Lists
Create an empty integer array.
Fill it partially with some data.The array component
without a number indicates allocated but unused space.
This is space you could have used for something better.
Add another element. We now have a full array to which
we can not add any more elements. We can delete or
replace, but we can not add.
lf the array is full, you can not add more elements,
because arrays have a fixed size. Linked Lists do not.
Another drawback of arrays is that if you delete an element from the middle and want no holes
in your array (e.g. (1, 2, 4, null) instead of (1, 2, null, 4)), you will need to shift everything after
the deleted element down in O(n) time. If you're trying to add an element somewhere other than
the very end of an array, you will need to shift some elements towards the end by one (also O(n)
time) to make room for the new element, and if you're writing an application which needs to
perform well and needs to do these operations often, you should consider using Linked Lists
instead. This should help you understand Linked Lists:
This is an empty linked list look like. The * is an
empty node (each element in a linked list called a
node) which has its next-node reference set to the
first node in the list. Since we don’t have a first
node, its next –node is a null pointer
This is a Linked List with three nodess. Each node
points to the next node in the chain. As mentioned
above, * is an empty node with a reference to the
first node. [3] is the last node in the chain with next
==null
Here we have delete node [2], so node [1]
(previosly pointing to [2]) now points to [3]. If we
didn’t change the refernce, node [3] and any nodes
behind it would have no references from your
program and get lost. If this happens and you’re
using C or C++, you have a memory leak. If
you’re using Java, the nodes would get
automatically garbage collected. Either way, make
sure you update the refernces!
For whatever reasons, we’ve decided to add node
[2] back nodes [1] and [3]. The reference from [1]
is set to [2], and the refence from [2] is set to the
old reference of [1], which is [3]
22
Pointers
Java does not have an explicit pointer type. Instead of pointers, all references to objects—
including variable assignments, arguments passed into methods and array elements—are
accomplished by using implicit references. References and pointers are essentially the same
thing except that you can’t do pointer arithmetic on references (nor do you need to).
Reference semantics also enable structures such as linked lists to be created easily in Java
without explicit pointers; merely create a linked list node with variables that point to the next and
the previous node. Then, to insert items in the list, assign those variables to other node
objects.
public class link {
public int value;
public link next;
// value of element
// reference to next
// constructor
public link(int n, link ln)
{
value = n;
next = ln;
}
public static void main(String args [])
{
// initialize list head
link head = null;
// add some entries to list
for (int i = 1; i <= 10; i++)
head = new link(i, head);
// dump out entries
link p = head;
while (p != null) {
System.out.println(p.value);
p = p.next;
}
}
}
Java does not have pointers, but instead uses implicit references. A line like:
link next;
Does not actually declare an object instance of class link, but rather a reference to an object
instance. The line:
head = new link(i, head);
23
Creates a new element for the list, sets its value, and then sets the object reference in "next" to
point at the old list head (this approach means that the last element inserted will be at the head of
the list). Saying:
p = p.next;
Simply picks up the "next" reference from the current node and makes it the current element
being worked on.
class Link
{
public int iData; // data item (key)
public double dData; // data item
public Link next; // next link in list
// ------------------------------------------------------------public Link(int id, double dd) // constructor
{
iData = id; // initialize data
dData = dd; // (‘next’ is automatically set to null)
}
// ------------------------------------------------------------public boolean isEmpty() // true if list is empty
{
return (first==null);
}
// -------------------------------------------------------------
The insertFirst() Method
The insertFirst() method of LinkList inserts a new link at the beginning of the list.
To insert the new link, we need only set the next field in the newly created link to point to the old
first link and then change first so it points to the newly created link. This situation is shown in
Figure below. The insertion it can be done in two steps:
1. Update the next link of a new node, to point to the current head node.
2. Update head link to point to the new node.
24
Inserting a new link.
// insert at start of list
public void insertFirst(int id, double dd)
{
// make new link
Link newLink = new Link(id, dd);
newLink.next = first;
// newLink --> old first
first = newLink;
// first --> newLink
}
25
Download