def k_smallest(A, k): """ Super-efficient (and easy to write) k-smallest selection for an arbitrary iterable. Time (and space) will be proportional to O(log k). """ from ch04.heap import PQ pq = PQ(k) # pq is a regular Max Binary Heap. Enqueue first k elements. If any # subsequent value is LARGER than our largest, it can be ignored, otherwise # remove the largest (since one is now smaller) and enqueue it. for v in A: if pq.N < k: pq.enqueue(v, v) else: if v < pq.peek().priority: # There is a chance to replace one of k-smallest values with this one pq.dequeue() pq.enqueue(v, v) result = [] while pq: result.append(pq.dequeue()) return list(reversed(result))
def initial_heap(): """Construct initial heap for figures.""" from ch04.heap import PQ h = PQ(31) for i in [15, 13, 14, 9, 11, 12, 14, 8, 2, 1, 10, 8, 6, 9, 7, 4, 5]: h.enqueue(i, i) return h
def iterator(pq): """ Provides a Python-generator over a PQ, using a PQ to do it! Each entry in the pqit iterator has (value, priority) where value is an index position into the original pq, while its priority is the priority if the entry. You can add capability for fail-fast iterators IF the heap actively increments a count in its pq.storage[0] which is unused anyway. Returned values include both the (value, priority) for maximum flexibility. """ from ch04.heap import PQ N = len(pq) # This works with INDEX positions into the heap pqit = PQ(N) pqit.enqueue(1, pq.peek().priority) while pqit: idx = pqit.dequeue() yield (pq.storage[idx].value, pq.storage[idx].priority) child = 2 * idx if child <= pq.N: pqit.enqueue(child, pq.storage[child].priority) child += 1 if child <= pq.N: pqit.enqueue(child, pq.storage[child].priority)
def guided_search(G, src, target, distance): """ Non-recursive depth-first search investigating given position. Needs a distance (node1, node2) function to determine distance between two nodes. Performance is O(N log N + E) since every edge is visited once for a directed graph and twice for an undirected graph. Each of the N nodes is processed by the priority queue, where dequeue() and enqueue() operations are each O(log N). While it is unlikely that the priority queue will ever contain N nodes, the worst case possibility always exists. """ from ch04.heap import PQ marked = {} node_from = {} pq = PQ(G.number_of_nodes()) marked[src] = True # Using a MAX PRIORITY QUEUE means we rely on negative distance to # choose the one that is closest... pq.enqueue(src, -distance(src, target)) while not pq.is_empty(): v = pq.dequeue() for w in G.neighbors(v): if not w in marked: node_from[w] = v marked[w] = True pq.enqueue(w, -distance(w, target)) return node_from
def guided_search(self, pos): """use Manhattan distance to maze end as priority in PQ to guide search.""" from ch04.heap import PQ pq = PQ(self.size) self.viewer.color_cell(pos, 'blue') src = self.start dist_to = {} dist_to[src] = 0 # Using a MAX PRIORITY QUEUE means we rely on negative distance to # choose the one that is closest... self.marked[src] = True pq.enqueue(src, -self.distance_to(src)) while not pq.is_empty(): cell = pq.dequeue() self.master.update() if self.refresh_rate: time.sleep(self.refresh_rate) if self.stop_end and cell == self.end: self.marked[cell] = True self.viewer.color_cell(cell, 'blue') return True for next_cell in self.g.neighbors(cell): if not next_cell in self.marked: self.node_from[next_cell] = cell dist_to[next_cell] = dist_to[cell] + 1 pq.enqueue(next_cell, -self.distance_to(next_cell)) self.marked[next_cell] = True self.viewer.color_cell(next_cell, 'blue') return False
def iterator_trial(): """Generate a sample Priority Queue and show iterator capability.""" from ch04.heap import PQ import random # populate pq = PQ(63) pq2 = PQ(63) for _ in range(63): prior = random.randint(0, 100) pq.enqueue(prior, prior) pq2.enqueue(prior, prior) for p in iterator(pq2): vp = pq.dequeue() if p[0] != vp: raise RuntimeError('Unexpected that iterator is different.')
def inspect_heap_array(): """ After inserting N elements in ascending order, is there a pattern in the values in the arrays in the heap? Same for inserting in descending order. """ from ch04.heap import PQ num = 31 pq = PQ(num) for i in range(1, num + 1): pq.enqueue(i, i) i = 1 rights = [] while i <= num: rights.append(pq.storage[i].value) i = (i * 2) + 1 print(rights) print([i.value for i in pq.storage[1:]]) pq = PQ(num) for i in range(num, 0, -1): pq.enqueue(i, i)