-
Notifications
You must be signed in to change notification settings - Fork 0
/
adaptive_huffman_coding.sf
82 lines (64 loc) · 1.68 KB
/
adaptive_huffman_coding.sf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#!/usr/bin/ruby
# Implementation of the Adaptive Huffman Coding.
# See also:
# https://rosettacode.org/wiki/huffman_coding
func walk(Hash n, String s, Hash h) {
if (n.has(:a)) {
h{n{:a}} = s
return nil
}
walk(n{:0}, s+'0', h) if n.has(:0)
walk(n{:1}, s+'1', h) if n.has(:1)
}
func mktree_from_freq(Hash freqs) {
var nodes = freqs.sort.flip.map_2d { |b,f|
Hash(a => b, freq => f)
}
loop {
nodes.sort_by!{|h| h{:freq} }
var(x, y) = (nodes.shift, nodes.shift)
if (defined(x)) {
if (defined(y)) {
nodes << Hash(:0 => x, :1 => y, :freq => x{:freq}+y{:freq})
}
else {
nodes << Hash(:0 => x, :freq => x{:freq})
}
}
nodes.len > 1 || break
}
var n = nodes.first
walk(n, '', n{:tree} = Hash())
return n
}
func encode(Array bytes, Array alphabet) {
var freq = alphabet.freq
var enc = []
bytes.each {|b|
var tree = mktree_from_freq(freq)
++freq{b}
enc << tree{:tree}{b}
}
return enc.join
}
func decode(String enc, Array alphabet) {
var out = []
var prefix = ''
var freq = alphabet.freq
var tree = mktree_from_freq(freq){:tree}.flip
enc.each {|bit|
prefix += bit
if (tree.has(prefix)) {
out << tree{prefix}
++freq{tree{prefix}}
tree = mktree_from_freq(freq){:tree}.flip
prefix = ''
}
}
return out
}
var text = "this is an example for huffman encoding"
var bytes = text.bytes
say var enc = encode(bytes, bytes.uniq)
say var dec = decode(enc, bytes.uniq).pack('C*')
assert_eq(dec, text)