Skip to content

Instantly share code, notes, and snippets.

@Andrelton
Created December 5, 2015 02:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Andrelton/dd874e9f3138f8931c18 to your computer and use it in GitHub Desktop.
Save Andrelton/dd874e9f3138f8931c18 to your computer and use it in GitHub Desktop.
Huffman Encoding Ruby Implementation
class Node
attr_reader :value, :left, :right
def initialize(value, left, right)
@value, @left, @right = value, left, right
end
end
class CountObject
attr_reader :char, :value
def initialize(char, value)
@char = char
@value = value
end
end
class HuffmanEncoder
def initialize(message, debug = false)
@message = message
@frequencies = Hash.new(0)
@count_objects = []
@node_queue = []
@binary_values = Hash.new
@debug = debug
end
def encode
collect_frequencies
sort_frequencies
create_count_objects
make_tree
collect_binary_values(@node_queue.first)
print_hash(@binary_values)
p generate_binary_string
end
def collect_frequencies
@message.each_char do |char|
@frequencies[char] += 1
end
end
def sort_frequencies
@frequencies = @frequencies.sort_by { |_, count| count }
end
def create_count_objects
@frequencies.each do |char, count|
@count_objects.push CountObject.new(char, count)
end
end
def make_tree
until @count_objects.empty? && @node_queue.count == 1
@node_queue.push(make_node)
end
@node_queue.each { |node| puts node.value.to_s + " characters." }
end
def make_node
left = find_min_value
right = find_min_value
total_value = left.value + right.value
return Node.new(total_value, left, right)
end
def find_min_value
return @count_objects.shift if @node_queue.empty?
return @node_queue.shift if @count_objects.empty?
if @count_objects[0].value <= @node_queue[0].value
puts "Taking a letter... #{@count_objects[0].char}" if @debug
return @count_objects.shift
else
puts "Joining nodes..." if @debug
return @node_queue.shift
end
end
def collect_binary_values(node, binary_string = "")
if node.is_a?(CountObject)
puts node.char if @debug
@binary_values[node.char] = binary_string
return
end
collect_binary_values(node.left, binary_string.dup << "0")
collect_binary_values(node.right, binary_string.dup << "1")
end
def generate_binary_string
encoded_string = ""
@message.each_char { |char| encoded_string << @binary_values[char] }
p encoded_string.length
return encoded_string
end
def print_hash(hash)
hash.each { |key, value| puts key + " " + value }
end
end
encoder = HuffmanEncoder.new("MISSISSIPPI_RIVER")
encoder.encode
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment