Skip to content

Commit 6a288b0

Browse files
committed
add huffman
1 parent a5ae8e9 commit 6a288b0

File tree

7 files changed

+343
-15
lines changed

7 files changed

+343
-15
lines changed

README.md

+7-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Try to keep the interface and variable name consistent with the original book wh
1414
## Note
1515

1616
Unlike Java or Python where you can put `main` function in a file directly. In `go` the `main` function has to be in the `main` package and in the **cmd** directory by convention.
17-
To test each algorithm(data structure), instead of running the file directly, you have to run the file under **cmd** directory. Example: [cmd/bag/main.go](algs4/cmd/bag/main.go)
17+
To test each algorithm(data structure), instead of running the file directly, you have to run the file under **cmd** directory. Example: [cmd/bag/main.go](cmd/bag/main.go)
1818

1919
## Index
2020

@@ -31,12 +31,12 @@ To test each algorithm(data structure), instead of running the file directly, yo
3131
* [Quick](algs4/quick.go)
3232
* [Quick3Way](algs4/quick_3way.go)
3333
* [MaxPQ](algs4/max_pq.go)
34-
* [TopM](algs4/cmd/topm/main.go)
34+
* [TopM](cmd/topm/main.go)
3535
* [IndexMinPQ](algs4/index_min_pq.go)
36-
* [Multiway](algs4/cmd/multiway/main.go)
36+
* [Multiway](cmd/multiway/main.go)
3737
* [Heap](algs4/heap.go)
3838
* 3 SEARCHING
39-
* [FrequencyCounter](algs4/cmd/frequency-counter/main.go)
39+
* [FrequencyCounter](cmd/frequency-counter/main.go)
4040
* [SequentialSearchST](algs4/sequential_search.go)
4141
* [BinarySearchST](algs4/binary_search_st.go)
4242
* [BST](algs4/bst.go)
@@ -52,7 +52,7 @@ To test each algorithm(data structure), instead of running the file directly, yo
5252
* [CC](algs4/cc.go)
5353
* [Cycle](algs4/cycle.go)
5454
* [SymbolGraph](algs4/symbol_graph.go)
55-
* [DegreesOfSeparation](algs4/cmd/degrees-of-separation/main.go)
55+
* [DegreesOfSeparation](cmd/degrees-of-separation/main.go)
5656
* Digraph
5757
* [Digraph](algs4/digraph.go)
5858
* [SymbolDigraph](algs4/symbol_digraph.go)
@@ -79,6 +79,8 @@ To test each algorithm(data structure), instead of running the file directly, yo
7979
* [TST](algs4/tst.go)
8080
* [KMP](algs4/kmp.go)
8181
* [NFA](algs4/nfa.go)
82+
* [Huffman](algs4/huffman.go)
83+
* [LZW](algs4/lzw.go)
8284

8385

8486
## License

algs4/binarystdin.go

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package algs4
2+
3+
import (
4+
"io"
5+
"os"
6+
"strings"
7+
)
8+
9+
// BinaryStdin ...
10+
var BinaryStdin = &binaryStdin{os.Stdin, 0, 0, false, nil}
11+
12+
type binaryStdin struct {
13+
br io.Reader
14+
buffer int // one character buffer
15+
n int // number of bits left in buffer
16+
isInitialized bool
17+
err error
18+
}
19+
20+
func (bs *binaryStdin) fillBuffer() {
21+
byte := make([]byte, 1)
22+
_, err := bs.br.Read(byte)
23+
if err != nil {
24+
if err == io.EOF{
25+
bs.err = io.EOF
26+
bs.n = -1
27+
} else {
28+
panic(err)
29+
}
30+
}
31+
bs.n = 8
32+
33+
bs.buffer = int(byte[0])
34+
}
35+
36+
// ReadBool reads the next bit of data from standard input and return as a boolean.
37+
func (bs *binaryStdin) ReadBool() bool {
38+
if bs.IsEmpty(){
39+
panic("reading from empty input stream")
40+
}
41+
bs.n--
42+
bit := (bs.buffer>>bs.n & 1) == 1
43+
if bs.n == 0 {
44+
bs.fillBuffer()
45+
}
46+
return bit
47+
}
48+
49+
// ReadInt reads the next 32 bits from standard input and return as a 32-bit int.
50+
func (bs *binaryStdin) ReadInt() int {
51+
if bs.IsEmpty(){
52+
panic("reading from empty input stream")
53+
}
54+
x := 0
55+
for i := 0; i < 4; i++ {
56+
b := bs.ReadByte()
57+
x <<= 8
58+
x |= int(b)
59+
}
60+
return x
61+
}
62+
63+
// ReadByte the next 8 bits from standard input and return as a byte
64+
func (bs *binaryStdin) ReadByte() byte {
65+
if bs.IsEmpty(){
66+
panic("reading from empty input stream")
67+
}
68+
if bs.n == 8 {
69+
b := byte(bs.buffer)
70+
bs.fillBuffer()
71+
return b
72+
}
73+
x := bs.buffer
74+
x <<= (8 - bs.n)
75+
oldN := bs.n
76+
bs.fillBuffer()
77+
bs.n = oldN
78+
x |= (bs.buffer >> bs.n)
79+
return byte(x)
80+
}
81+
82+
// ReadString reads the remaining bytes of data from standard input and return as a string.
83+
func (bs *binaryStdin) ReadString() string {
84+
if bs.IsEmpty(){
85+
panic("reading from empty input stream")
86+
}
87+
88+
var sb strings.Builder
89+
for !bs.IsEmpty() {
90+
b := bs.ReadByte()
91+
sb.WriteString(string(b))
92+
}
93+
return sb.String()
94+
}
95+
96+
func (bs *binaryStdin) initialize(){
97+
bs.fillBuffer()
98+
bs.isInitialized = true
99+
}
100+
101+
// IsEmpty ...
102+
func (bs *binaryStdin) IsEmpty() bool {
103+
if !bs.isInitialized {
104+
bs.initialize()
105+
}
106+
return bs.err == io.EOF
107+
}

algs4/binarystdout.go

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package algs4
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
)
8+
9+
// BinaryStdout ...
10+
var BinaryStdout = binaryStdout{os.Stdout, 0, 0}
11+
12+
type binaryStdout struct {
13+
out io.Writer
14+
buffer int // 8-bit buffer of bits to write
15+
n int // number of bits remaining in buffer
16+
}
17+
// WriteInt writes the 32-bit int to standard output
18+
func (bs *binaryStdout)WriteInt(x int)error{
19+
bs.WriteByte(byte((x >> 24) & 0xff))
20+
bs.WriteByte(byte((x >> 16) & 0xff))
21+
bs.WriteByte(byte((x >> 8) & 0xff))
22+
bs.WriteByte(byte((x >> 0) & 0xff))
23+
return nil
24+
}
25+
26+
// Close ...
27+
func (bs *binaryStdout)Close(){
28+
bs.clearBuffer()
29+
}
30+
31+
// Write...
32+
func (bs *binaryStdout) Write(p []byte) error {
33+
return nil
34+
}
35+
36+
37+
// WriteByte writes the 8-bit byte to standard output.
38+
func (bs *binaryStdout) WriteByte(b byte) error {
39+
if !(int(b) >= 0 && int(b) < 256) {
40+
panic("invalid byte")
41+
}
42+
// // optimized if byte-aligned
43+
// if bs.n == 0 {
44+
// _, err := bs.out.Write([]byte{b})
45+
// if err != nil {
46+
// fmt.Println("write byte to stdout error: ", err)
47+
// return err
48+
// }
49+
// }
50+
for i := 0; i < 8; i++ {
51+
bit := ((int(b) >> (8 - i - 1)) & 1) == 1
52+
bs.WriteBit(bit)
53+
}
54+
return nil
55+
}
56+
57+
// WriteBit writes the specified bit to standard output.
58+
func (bs *binaryStdout) WriteBit(bit bool) error {
59+
bs.buffer <<= 1
60+
if bit {
61+
bs.buffer |= 1
62+
}
63+
bs.n++
64+
if bs.n == 8 {
65+
return bs.clearBuffer()
66+
}
67+
return nil
68+
}
69+
70+
func (bs *binaryStdout) clearBuffer() error {
71+
if bs.n == 0 {
72+
return nil
73+
}
74+
if bs.n > 0 {
75+
bs.buffer <<= (8 - bs.n)
76+
}
77+
_, err := bs.out.Write([]byte{byte(bs.buffer)})
78+
if err != nil {
79+
fmt.Println("write byte to stdout error: ", err)
80+
panic("err")
81+
}
82+
bs.n = 0
83+
bs.buffer = 0
84+
return nil
85+
}

huffman.go algs4/huffman.go

+53-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package algs4
22

33
import (
44
"fmt"
5-
"github.com/shellfly/algo/stdin"
65
)
76

87
type huffmanNode struct {
@@ -24,7 +23,7 @@ func (hn *huffmanNode) CompareTo(other interface{}) int {
2423
return 0
2524
}
2625
func (hn *huffmanNode) String() string {
27-
return fmt.Sprintf("%s-%s", hn.ch, hn.freq)
26+
return fmt.Sprintf("%c-%d-(%v-%v)", hn.ch, hn.freq, hn.left, hn.right)
2827
}
2928

3029
// Huffman ...
@@ -39,36 +38,35 @@ func NewHuffman() *Huffman {
3938

4039
// Compress ...
4140
func (h Huffman) Compress() {
42-
s := stdin.NewStdIn().ReadString()
41+
s := BinaryStdin.ReadString()
4342
freq := make([]int, h.R)
4443
for i := 0; i < len(s); i++ {
4544
freq[s[i]]++
4645
}
4746
// build huffman trie
48-
root := buildTrie(freq)
47+
root := h.buildTrie(freq)
4948

5049
// build code table
5150
st := make([]string, h.R)
5251
h.buildCode(st, root, "")
53-
5452
// print trie for decoder
5553
h.writeTrie(root)
5654

5755
// print number of bytes in original uncompressed message
58-
fmt.Println(len(s))
56+
BinaryStdout.WriteInt(len(s))
5957

6058
// use Huffman code to encode input
6159
for i := 0; i < len(s); i++ {
6260
code := st[s[i]]
6361
for j := 0; j < len(code); j++ {
6462
if string(code[j]) == "0" {
65-
fmt.Print(0)
63+
BinaryStdout.WriteBit(false)
6664
} else if string(code[j]) == "1" {
67-
fmt.Print(1)
65+
BinaryStdout.WriteBit(true)
6866
}
6967
}
7068
}
71-
fmt.Println(s)
69+
BinaryStdout.Close()
7270
}
7371

7472
func (h Huffman) buildTrie(freq []int) *huffmanNode {
@@ -86,3 +84,49 @@ func (h Huffman) buildTrie(freq []int) *huffmanNode {
8684
}
8785
return pq.DelMin().(*huffmanNode)
8886
}
87+
88+
func (h Huffman) writeTrie(x *huffmanNode) {
89+
if x.isLeaf() {
90+
BinaryStdout.WriteBit(true)
91+
BinaryStdout.WriteByte(x.ch)
92+
return
93+
}
94+
BinaryStdout.WriteBit(false)
95+
h.writeTrie(x.left)
96+
h.writeTrie(x.right)
97+
}
98+
99+
func (h Huffman) buildCode(st []string, x *huffmanNode, s string) {
100+
if !x.isLeaf() {
101+
h.buildCode(st, x.left, s+"0")
102+
h.buildCode(st, x.right, s+"1")
103+
} else {
104+
st[x.ch] = s
105+
}
106+
}
107+
108+
// Expand ...
109+
func (h Huffman) Expand() {
110+
root := readTrie()
111+
length := BinaryStdin.ReadInt()
112+
for i := 0; i < length; i++ {
113+
x := root
114+
for !x.isLeaf() {
115+
bit := BinaryStdin.ReadBool()
116+
if bit {
117+
x = x.right
118+
} else {
119+
x = x.left
120+
}
121+
}
122+
BinaryStdout.WriteByte(x.ch)
123+
}
124+
}
125+
126+
func readTrie() *huffmanNode {
127+
isLeaf := BinaryStdin.ReadBool()
128+
if isLeaf {
129+
return &huffmanNode{BinaryStdin.ReadByte(), -1, nil, nil}
130+
}
131+
return &huffmanNode{'0', -1, readTrie(), readTrie()}
132+
}

algs4/stack.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func NewStack() *Stack {
1414

1515
// Push ...
1616
func (s *Stack) Push(item interface{}) {
17-
s.LinkList.Add(item)
17+
s.Add(item)
1818
}
1919

2020
// Pop ...

0 commit comments

Comments
 (0)