Priority Queue

A binary heap is a common way of implementing priority queues. It has two additional constracints of a binaray tree.

  • It is a complete binary tree so fully balanced.
  • All the nodes are greater or equal to their children.

The binary heap can be represented as a simple array. The children of an element at a given index i will always be in 2i and 2i+1. The parent of the node is at the index i/2

Implementation

class PriorityQueue
    attr_accessor :queue

    def initialize
        @queue = [nil]
    end

    # element should be inserted in the right place
    def <<(element)
        @queue << element

        bubble_up(@queue.size - 1)
    end

    private
        # exchange the elements if current element at index
        # is smaller than it's parent
        def bubble_up(index)
            parent_index = (index / 2)

            # base cases
            return if index == 1 
            return if @queue[parent_index] >= @queue[index] 

            # exchange elements
            @queue[index], @queue[parent_index] = @queue[parent_index], @queue[index]

            # recursive call
            bubble_up(parent_index)
        end
end

q = PriorityQueue.new
q << 10
q << 5
q << 7
# => [nil, 10, 7, 5]
class PriorityQueue

    # ...

    def pop
        # exchange first and last elements
        @queue[1], @queue[@queue.size - 1] = 
        @queue[@queue.size - 1], @queue[1]

        # remove the last element from the queue
        result = @queue.pop

        # recursive call
        bubble_down(1)
        
        return result
    end

    private 
    
        # ...

        def bubble_down(index)
            child_index = (index * 2)

            return if child_index > @queue.size - 1

            child_left = @queue[child_index]
            child_right = @queue[child_index + 1]

            # if both children not empty then
            # compare left and right
            if child_left != nil && child_right != nil
                child_index += 1 if child_right > child_left
            # if left child is nil then right child is selected
            # no need to check if child_right is nil
            # since child_index is already pointing to left child
            elsif child_left.nil?
                child_index += 1
            end

            # if current is bigger then return
            # else excahnge and bubble down again
            if @queue[index] >= @queue[child_index]
                return
            else
                @queue[index], @queue[child_index] = @queue[child_index], @queue[index]
                bubble_down(child_index)
            end
        end
end

q = PriorityQueue.new
q << 10
q << 5
q << 7
# => [nil, 10, 7, 5]

p q.pop # => 10
p q.pop # => 7
p q.pop # => 5

Taeyang Lee

Taeyang Lee
I really enjoy taking on tasks which are out of my comfort zone and using them as a great way to learn the necessary tools to complete it.

Monads

Published on December 17, 2018

Functors

Published on December 16, 2018