24
Computer Science 112 Fundamentals of Programming II Queues and Priority Queues

Computer Science 112 Fundamentals of Programming II Queues and Priority Queues

Embed Size (px)

Citation preview

Computer Science 112

Fundamentals of Programming IIQueues and Priority Queues

Queues: Formal Properties

• A queue is a linear collection that supports first-in, first-out (FIFO) access

• Insertions occur at one end, called the rear

• Removals occur at the other end, called the front

FIFO Access

D

D

D

D

D D D

add

D

D

Dremove

Rear of queue

Front of queue

q.isEmpty() Returns True if empty, False otherwise

len(q) Returns the number of items in the queue

str(q) Returns a string representation

iter(q) Supports a for loop

item in q True if item is in queue, False otherwise

q1 + q2 Returns a new queue with items in q1 and q2

q1 == q2 Equality test for two queues

Minimal Set of Queue Operations

q.isEmpty() Returns True if empty, False otherwise

len(q) Returns the number of items in the queue

str(q) Returns a string representation

iter(q) Supports a for loop

item in q True if item is in queue, False otherwise

q1 + q2 Returns a new queue with items in q1 and q2

q1 == q2 Equality test for two queues

q.add(item) Adds item to the rear of the queue

q.pop() Removes and returns front item

q.peek() Returns item at the front of the queue

The precondition of pop and peek is that the queue is not empty.

Minimal Set of Queue Operations

Queue Implementations

• Array-based

• Linked (singly, with an extra tail pointer: the head is the front and the tail is the rear)

A Realistic Queue Implementation

AbstractCollection

object

AbstractQueue

ArrayQueue LinkedQueue

queue = LinkedQueue([45, 66, 99])

while not queue.isEmpty()): print(queue.pop())

Example Use of a Queue

from node import Nodefrom abstractqueue import AbstractQueue

class LinkedQueue(AbstractQueue):

def __init__(self, sourceCollection = None) self._front = self._rear = None AbstractQueue.__init__(self, sourceCollection)

The Linked Implementation

5 4 3 2frontrear

from node import Nodefrom abstractqueue import AbstractQueue

class LinkedQueue(AbstractQueue):

def __init__(self, sourceCollection = None): self._front = self._rear = None AbstractQueue.__init__(self, sourceCollection)

def add(self, item): newNode = Node(item) if self.isEmpty(): self._front = newNode else: self._rear.next = newNode self._rear = newNode self._size += 1

The Linked Implementation

Queue Applications

Queues are useful for algorithms that serve clients on a first-come first-served basis– Process scheduling in operating systems– Modeling and simulation of real-world

processes, such as supermarket checkout situations

Priority Queues

• Similar to a queue, except that items can grouped by priority for earlier service

• Elements are maintained in sorted order, with the smallest ones having the highest priority

• When two elements have the same priority, they are served in FIFO order

Priority Queue ADT: Implementations

• Commonly implemented with a heap (will discuss in several weeks)

• A linked priority queue is a type of linked queue that imposes a priority ordering on its elements

• Can inherit the data and most of the behavior of a linked queue

Place in the Queue Hierarchy

LinkedPriorityQueue

All operations except add are the same as in LinkedQueue

The element type must be comparable

AbstractCollection

object

AbstractQueue

ArrayQueue LinkedQueue

LinkedPriorityQueue

• Extends LinkedQueue

• Overrides the add method

• Otherwise, the behavior is the same!

Strategy for add

• If queue is empty or the new item >= the rear item, call LinkedQueue.add

• Otherwise, use a probe and trailer to search for the first item > the new item

• Insert the new item before that item

LinkedPriorityQueuefrom node import Nodefrom linkedqueue import LinkedQueue

class LinkedPriorityQueue(LinkedQueue):

def __init__(self, sourceCollection = None): LinkedQueue.__init__(self, sourceCollection)

def add(self, item): if self.isEmpty() or item >= the last one LinkedQueue.add(self, item) elif item < the first one insert at head else: initialize a probe and a trailer while item >= data advance trailer and probe newNode = Node(item, probe) insert between probe and trailer

+ and __add__

>> q1 = LinkedQueue([2, 4, 6])

>> q2 = LinkedQueue([1, 3, 5])

>> print(q1 + q2)[2, 4, 6, 1, 3, 5]

+ maintains FIFO order for plain queues

Uses __add__ method in AbstractCollection

+ and __add__

>> q1 = LinkedPriorityQueue([2, 4, 6])

>> q2 = LinkedPriorityQueue([1, 3, 5])

>> print(q1 + q2)[1, 2, 3, 4, 5, 6]

+ maintains sorted order for priority queues

Uses __add__ method in AbstractCollection

The Comparable Wrapper Class

• Provides an easy way to tag existing objects with priority values, if those objects are not already comparable

• Or can override the existing ordering of comparable objects, if needed

• Provides the conventional interface for the comparison operators and str

Using Comparablepq = LinkedPriorityQueue()

pq.add("Ken")pq.add("Sam")pq.add("Ann")

for item in pq: print(item)

Using Comparable

pq = LinkedPriorityQueue()

pq.add(Comparable("Ken", 2))pq.add(Comparable("Sam", 1))pq.add(Comparable("Ann", 2))

for item in pq: print(item)

pq = LinkedPriorityQueue()

pq.add("Ken")pq.add("Sam")pq.add("Ann")

for item in pq: print(item)

Defining Comparableclass Comparable(object):

def __init__(self, data, priority = 1): self.data = data self.priority = priority

def __str__(self): return str(self.data)

def __eq__(self, other): if self is other: return True if type(self) != type(other): return False return self.priority == other.priority def __lt__(self, other): return self.priority < other.priority

def __le__(self, other): return self.priority <= other.priority

For Monday (after break)

Array-Based Queues