6.5 Priority queues

6.5-1

Alt text

Alt text

Alt text

6.5-2

Alt text

Alt text

Alt text

Alt text

6.5-3

HEAP-MINIMUM(A)
    return A[1]
HEAP-EXTRACT-MIN(A)
    if A.heap-size < 1
        error "heap underflow"
    min = A[1]
    A[1] = A[A.heap-size]
    A.heap-size = A.heap-size - 1
    MIN-HEAPIFY(A, 1)
    return max
HEAP-DECREASE-KEY(A, i, key)
    if key > A[i]
        error "new key is bigger than current key"
    A[i] = key
    while i > 1 and A[PARENT(i)] > A[i]
        exchange A[i] with A[PARENT(i)]
        i = PARENT(i)
MIN-HEAP-INSERT(A, key)
    A.heap-size = A.heap-size + 1
    A[A.heap-size] = +∞
    HEAP-DECREASE-KEY(A, A.heap-size, key)

6.5-4

Setting the key of the inserted node to negative infinity to make sure it can pass the truth check in line 1 of HEAP-INCREASE-KEY(A, i, key).

6.5-5

Initialization: Prior to the first iteration of the loop, the subarray A[1..A.heap-size] is satifies the max-heap before we set A[i] = key, after we set A[i] = key, it's possible that A[i] would be greater than its parent. And we cannot set a smaller key to A[i], so there may be only one violation.

Maintenance: In the for loop, we are exchanging A[i] and A[PARENT(i)], before the exchange, the subtree rooted at A[i] is a max-heap, but it may be greater than its parent, so there may be on violation.

Termination: When it's terminated, i maybe 1 or A[i] is smaller thant its parent, either makes A a max-heap.

6.5-6

HEAP-INCREASE-KEY(A, i, key)
if key < A[i]
    error "new key is smaller than current key"
while i > 1 and A[PARENT(i)] < key
    A[i] = A[PARENT(i)]
    i = PARENT(i)
A[i] = key

6.5-7

Implement a first-in, first-out queue with a min priority queue. Call MIN-HEAP-INSERT method to enqueue with a priority, for example, use timestamp as priority. Call HEAP-MINIMUM to dequeue.

Implement a stack with a max priority queue. Call MAX-HEAP-INSERT method to push with a priority, for example, use timestamp as priority. Call HEAP-MAXIMUM to pop.

6.5-8

HEAP-DELETE(A, i)
A.heap-size < 1
    error "heap underflow"
A[i] = A[A.heap-size]
A.heap-size = A.heap-size - 1
MAX-HEAPIFY(A, i)

6.5-9

First we create a k-elements min heap from the first element in each sorted list, this requires $O(k) + O(n) = O(n)$.

Then we keep extracting the min value from min heap, and insert the next value after the min value in the original list, this requires $O(\lg{k})$. And there are n elements, so it requires $O(n\lg{k})$.

Thus the running time is $O(n) + O(n\lg{k}) = O(n\lg{k})$.

def merge_sorted_lists(lists):
    sorted_list = []
    min_heap_elements = []

    for i in range(len(lists)):
        min_heap_elements.append(MinHeapElement(i, 1, lists[i][0]))

    min_heap = MinHeap(min_heap_elements)

    while not min_heap.is_empty():
        min_element = min_heap.extract_min()
        sorted_list.append(min_element.value)

        list_index = min_element.list_index
        next_index = min_element.next_index

        if next_index < len(lists[list_index]):
            next_element = MinHeapElement(
                list_index, next_index + 1, lists[list_index][next_index])

            min_heap.insert(next_element)

    return sorted_list


class MinHeapElement():
    def __init__(self, list_index, next_index, value):
        self.list_index = list_index
        self.next_index = next_index
        self.value = value


class MinHeap():
    def __init__(self, elements):
        self.elements = elements
        self.heap_size = len(elements)

        self.build_min_heap()

    def extract_min(self):
        assert not self.is_empty()

        minimum = self.elements[0]
        self.elements[0] = self.elements[self.heap_size - 1]
        self.heap_size -= 1

        self.min_heapify(0)

        return minimum

    def insert(self, element):
        self.heap_size += 1

        if len(self.elements) < self.heap_size:
            self.elements.append(element)
        else:
            self.elements[self.heap_size - 1] = element

        self.decrease_element(self.heap_size - 1, element)

    def decrease_element(self, i, element):
        assert i < self.heap_size
        assert element.value <= self.elements[i].value

        while i > 0 and self.elements[(i - 1) // 2].value > element.value:
            self.elements[i] = self.elements[(i - 1) // 2]
            i = (i - 1) // 2

        self.elements[i] = element

    def is_empty(self):
        return self.heap_size == 0

    def min_heapify(self, i):
        left = 2 * i + 1
        right = 2 * i + 2
        minimum = i

        if (left <= self.heap_size - 1 and
                self.elements[left].value < self.elements[i].value):
            minimum = left

        if (right <= self.heap_size - 1 and
                self.elements[right].value < self.elements[minimum].value):
            minimum = right

        if minimum != i:
            self.elements[i], self.elements[minimum] = \
                self.elements[minimum], self.elements[i]

            self.min_heapify(minimum)

    def build_min_heap(self):
        for i in range((self.heap_size - 1) // 2, -1, -1):
            self.min_heapify(i)