arnaucube
arnaucube/huffman-codingPublic Self-hosted repository
huffman-coding/huffman.go
huffman.goRaw
 1package huffman
 2
 3import (
 4	"fmt"
 5	"sort"
 6)
 7
 8const (
 9	LEAF = 0
10	MID  = 1
11)
12
13type Node struct {
14	typ  int64
15	key  int64
16	leaf byte
17	l    *Node
18	r    *Node
19}
20
21func (n *Node) String() string {
22	if n.typ == LEAF {
23		return fmt.Sprintf("%s (%v)", string(n.leaf), n.key)
24	}
25	return fmt.Sprintf("%v", n.key)
26}
27
28func newLeaf(b byte, k int64) *Node {
29	return &Node{
30		typ:  LEAF,
31		key:  k,
32		leaf: b,
33	}
34}
35
36func newNode(a, b *Node) *Node {
37	var l, r *Node
38	if a.key < b.key {
39		l = a
40		r = b
41	} else {
42		l = b
43		r = a
44	}
45	n := &Node{
46		typ: MID,
47		key: a.key + b.key,
48		l:   l,
49		r:   r,
50	}
51	return n
52}
53
54func leafsFromValues(values map[byte]int64) []*Node {
55	var nodes []*Node
56	for k, v := range values {
57		n := newLeaf(k, v)
58		nodes = append(nodes, n)
59	}
60	return nodes
61}
62
63func rmFromNodes(i int, nodes []*Node) []*Node {
64	if i == len(nodes) {
65		return nodes[:i]
66	}
67	return append(nodes[:i], nodes[i+1:]...)
68}
69
70// sortNodes returns a []*Node sorted
71func sortNodes(nodes []*Node) []*Node {
72	sort.Slice(nodes, func(i, j int) bool {
73		return nodes[i].key < nodes[j].key
74	})
75	return nodes
76}
77
78func buildTree(nodes []*Node) *Node {
79	// build binary tree
80	for len(nodes) > 1 {
81		// pair two smallest nodes
82		nodes = sortNodes(nodes)
83		// create a new node with them
84		n := newNode(nodes[0], nodes[1])
85		// remove the picked nodes from the array of nodes
86		nodes = rmFromNodes(0, nodes)
87		nodes = rmFromNodes(0, nodes)
88		// add the new node (the two old paired) to the node array
89		nodes = append(nodes, n)
90	}
91	return nodes[0]
92}