package huffman
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
)
|
|
|
|
const (
|
|
LEAF = 0
|
|
MID = 1
|
|
)
|
|
|
|
type Node struct {
|
|
typ int64
|
|
key int64
|
|
leaf byte
|
|
l *Node
|
|
r *Node
|
|
}
|
|
|
|
func (n *Node) String() string {
|
|
if n.typ == LEAF {
|
|
return fmt.Sprintf("%s (%v)", string(n.leaf), n.key)
|
|
}
|
|
return fmt.Sprintf("%v", n.key)
|
|
}
|
|
|
|
func newLeaf(b byte, k int64) *Node {
|
|
return &Node{
|
|
typ: LEAF,
|
|
key: k,
|
|
leaf: b,
|
|
}
|
|
}
|
|
|
|
func newNode(a, b *Node) *Node {
|
|
var l, r *Node
|
|
if a.key < b.key {
|
|
l = a
|
|
r = b
|
|
} else {
|
|
l = b
|
|
r = a
|
|
}
|
|
n := &Node{
|
|
typ: MID,
|
|
key: a.key + b.key,
|
|
l: l,
|
|
r: r,
|
|
}
|
|
return n
|
|
}
|
|
|
|
func leafsFromValues(values map[byte]int64) []*Node {
|
|
var nodes []*Node
|
|
for k, v := range values {
|
|
n := newLeaf(k, v)
|
|
nodes = append(nodes, n)
|
|
}
|
|
return nodes
|
|
}
|
|
|
|
func rmFromNodes(i int, nodes []*Node) []*Node {
|
|
if i == len(nodes) {
|
|
return nodes[:i]
|
|
}
|
|
return append(nodes[:i], nodes[i+1:]...)
|
|
}
|
|
|
|
// sortNodes returns a []*Node sorted
|
|
func sortNodes(nodes []*Node) []*Node {
|
|
sort.Slice(nodes, func(i, j int) bool {
|
|
return nodes[i].key < nodes[j].key
|
|
})
|
|
return nodes
|
|
}
|
|
|
|
func buildTree(nodes []*Node) *Node {
|
|
// build binary tree
|
|
for len(nodes) > 1 {
|
|
// pair two smallest nodes
|
|
nodes = sortNodes(nodes)
|
|
// create a new node with them
|
|
n := newNode(nodes[0], nodes[1])
|
|
// remove the picked nodes from the array of nodes
|
|
nodes = rmFromNodes(0, nodes)
|
|
nodes = rmFromNodes(0, nodes)
|
|
// add the new node (the two old paired) to the node array
|
|
nodes = append(nodes, n)
|
|
}
|
|
return nodes[0]
|
|
}
|
|
|
|
func descendTable(n *Node, path string, table map[byte]string) map[byte]string {
|
|
if n.typ == MID {
|
|
table = descendTable(n.l, path+"0", table)
|
|
table = descendTable(n.r, path+"1", table)
|
|
} else if n.typ == LEAF {
|
|
table[n.leaf] = path
|
|
}
|
|
return table
|
|
}
|
|
|
|
func generateTable(n *Node) map[byte]string {
|
|
table := make(map[byte]string)
|
|
table = descendTable(n, "", table)
|
|
return table
|
|
}
|
|
|
|
func Huffman(b []byte) error {
|
|
// compute frequencies
|
|
values := make(map[byte]int64)
|
|
for _, v := range b {
|
|
values[v]++
|
|
}
|
|
leafs := leafsFromValues(values)
|
|
|
|
// sort frequencies
|
|
sortedLeafs := sortNodes(leafs)
|
|
|
|
// build binary tree
|
|
n := buildTree(sortedLeafs)
|
|
fmt.Println(n)
|
|
|
|
// get the table (binary code for each value)
|
|
table := generateTable(n)
|
|
fmt.Println(table)
|
|
|
|
// WIP
|
|
|
|
return nil
|
|
}
|