Skip to content

Instantly share code, notes, and snippets.

@lfborjas
Created July 24, 2012 20:35
Show Gist options
  • Save lfborjas/3172495 to your computer and use it in GitHub Desktop.
Save lfborjas/3172495 to your computer and use it in GitHub Desktop.
Compresses a string using the literal approach to huffman encoding
def freq_table(str)
str.each_char.inject(Hash.new(0)) do |table, char|
table[char] += 1
table
end.sort_by(&:last).reverse
end
def build_tree(freq_table)
until freq_table.size == 1
less_frequent = 2.times.map{ freq_table.pop }
left, right = less_frequent
new_node = [
less_frequent.map(&:first).join(","),
left, right,
less_frequent.map(&:last).inject(:+)
]
freq_table.push new_node
end
freq_table.first
end
def draw_tree(tree)
chars = tree.shift
freq = tree.pop
left, right = tree
label = %Q{"{#{chars.gsub(/\s+/, "_")}}:#{freq}"}
if [left, right].all?(&:nil?)
label
else
"#{label}->#{draw_tree(left)};#{label}->#{draw_tree(right)}"
end
end
def draw(dot)
File.open("dotit", 'w') do |f|
f.write("digraph{#{dot}}")
end
`dot -Tpng dotit -o dotted.png && open dotted.png`
end
def encode(table, tree, acum = "")
chars = tree.shift
freq = tree.pop
left, right = tree
unless [left, right].all?(&:nil?)
encode table, left, acum + "0"
encode table, right, acum + "1"
else
table[chars] = acum
end
end
def huffman_codes(tree)
codes = {}
encode(codes, tree)
codes
end
def compress(str)
tree = build_tree(freq_table(str))
draw(draw_tree(tree))
codes = huffman_codes(build_tree(freq_table(str)))
puts "The huffman codes are: #{codes.inspect}"
str.each_char.map do |char|
codes[char]
end.join("")
end
puts "The compressed string is", compress(ARGV.pop)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment