55 lines
1.1 KiB
Ruby
55 lines
1.1 KiB
Ruby
require 'priority_queue'
|
|
|
|
def huffman_encoding(str)
|
|
char_count = Hash.new(0)
|
|
str.each_char {|c| char_count[c] += 1}
|
|
|
|
pq = CPriorityQueue.new
|
|
# chars with fewest count have highest priority
|
|
char_count.each {|char, count| pq.push(char, count)}
|
|
|
|
while pq.length > 1
|
|
key1, prio1 = pq.delete_min
|
|
key2, prio2 = pq.delete_min
|
|
pq.push([key1, key2], prio1 + prio2)
|
|
end
|
|
|
|
Hash[*generate_encoding(pq.min_key)]
|
|
end
|
|
|
|
def generate_encoding(ary, prefix="")
|
|
case ary
|
|
when Array
|
|
generate_encoding(ary[0], "#{prefix}0") + generate_encoding(ary[1], "#{prefix}1")
|
|
else
|
|
[ary, prefix]
|
|
end
|
|
end
|
|
|
|
def encode(str, encoding)
|
|
str.each_char.collect {|char| encoding[char]}.join
|
|
end
|
|
|
|
def decode(encoded, encoding)
|
|
rev_enc = encoding.invert
|
|
decoded = ""
|
|
pos = 0
|
|
while pos < encoded.length
|
|
key = ""
|
|
while rev_enc[key].nil?
|
|
key << encoded[pos]
|
|
pos += 1
|
|
end
|
|
decoded << rev_enc[key]
|
|
end
|
|
decoded
|
|
end
|
|
|
|
str = "this is an example for huffman encoding"
|
|
encoding = huffman_encoding(str)
|
|
encoding.to_a.sort.each {|x| p x}
|
|
|
|
enc = encode(str, encoding)
|
|
dec = decode(enc, encoding)
|
|
puts "success!" if str == dec
|