예제 #1
0
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))
예제 #2
0
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
예제 #3
0
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)
예제 #4
0
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
예제 #5
0
    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
예제 #6
0
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.')
예제 #7
0
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)