# This module defines the classes Stack, Queue, and PriorityQueue #---------------------------------------------------------------------- class Stack: """ A simple list implementation of a stack. Interface methods: s.isEmpty() returns True if s is empty s.insert(x) inserts x into s at the front s.remove() removes and returns the first element from s """ def __init__(self): self.contents = [] def isEmpty(self): return len(self.contents) == 0 def remove(self): if self.isEmpty(): return None else: return self.contents.pop(0) def insert(self, new): self.contents.insert(0, new) #---------------------------------------------------------------------- class Queue: """ A simple list implementation of a queue. Interface methods: q.isEmpty() returns True if q is empty q.insert(x) inserts x into q at the end q.remove() removes and returns the first element from q """ def __init__(self): self.contents = [] def isEmpty(self): return len(self.contents) == 0 def remove(self): if self.isEmpty(): return None else: return self.contents.pop(0) def insert(self, new): self.contents.append(new) #---------------------------------------------------------------------- class PriorityQueue: """ This is a heap implementation of a priority queue. The insert and remove operations each take O(log n) time. To create a new priority queue, call the constructor with a function that maps queue elements to cost values. Interface methods: q.isEmpty() returns True if q is empty q.insert(x) inserts x into q according to the cost of x q.remove() removes and returns the lowest-cost element from q Example: q = PriorityQueue(lambda x: x) q.insert(5) q.insert(1) q.insert(3) q.insert(8) q.insert(2) print q.remove() ==> 1 print q.remove() ==> 2 print q.remove() ==> 3 print q.remove() ==> 5 print q.remove() ==> 8 print q.remove() ==> None """ # costFunction is a function that maps queue elements to cost values def __init__(self, costFunction): # current number of elements in queue self.size = 0 # current maximum size of queue (can be changed - see insert below) self.limit = 10 # the elements themselves (position 0 is not used) self.contents = [None] * (self.limit + 1) # a function that returns the cost of the element at position i self.cost = lambda i: costFunction(self.contents[i]) def isEmpty(self): # returns True if the queue is empty, or else False return self.size == 0 def isRoot(self, i): # returns True if element i is the root of the heap return i == 1 def isLeaf(self, i): # returns True if element i is a leaf return self.left(i) == None and self.right(i) == None def parent(self, i): # returns the position of the parent of element i return i / 2 def left(self, i): # returns the position of the left child of element i child = i * 2 if child > self.size: return None else: return child def right(self, i): # returns the position of the right child of element i child = i * 2 + 1 if child > self.size: return None else: return child def smallestChild(self, i): # returns the position of the smallest child of element i leftChild = self.left(i) rightChild = self.right(i) if leftChild == None: return rightChild elif rightChild == None: return leftChild elif self.cost(leftChild) < self.cost(rightChild): return leftChild else: return rightChild def swap(self, i, j): # swaps elements in positions i and j (using parallel assignment) self.contents[i], self.contents[j] = self.contents[j], self.contents[i] def insert(self, new): # inserts a new element into the heap if self.size == self.limit: # this doubles the amount of space available in self.contents self.contents.extend([None] * self.size) self.limit += self.size self.size += 1 self.contents[self.size] = new # push new element up toward the root as far as possible current = self.size while not self.isRoot(current): parent = self.parent(current) if self.cost(current) >= self.cost(parent): return self.swap(current, parent) current = parent def remove(self): # deletes the current element at the root of the heap and returns it if self.size == 0: return None else: min = self.contents[1] self.contents[1] = self.contents[self.size] self.size -= 1 # push new root element down into the heap as far as possible current = 1 while not self.isLeaf(current): child = self.smallestChild(current) if self.cost(current) <= self.cost(child): return min self.swap(current, child) current = child return min