Skip to content

Commit 3ed6912

Browse files
committed
Add JS example for Huffman Encoding
1 parent 259b482 commit 3ed6912

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
function encode(str) {
2+
const tree = createTree(str);
3+
const codebook = createCodebook(tree);
4+
return {
5+
string: [...str].map(c => codebook[c]).join(""),
6+
tree,
7+
codebook
8+
};
9+
10+
function createTree(str) {
11+
const chars = [...str];
12+
const charCounts = chars.reduce((counts, char) => {
13+
counts[char] = (counts[char] || 0) + 1;
14+
return counts;
15+
}, {});
16+
17+
const nodes = Object.entries(charCounts).map(([key, weight]) => ({ key, weight }));
18+
const priorityQueue = makeQueue(nodes);
19+
while (priorityQueue.data.length > 1) {
20+
const left = priorityQueue.dequeue();
21+
const right = priorityQueue.dequeue();
22+
priorityQueue.enqueue({ weight: left.weight + right.weight, left, right });
23+
}
24+
return priorityQueue.dequeue();
25+
}
26+
27+
function createCodebook(tree) {
28+
return function recurse(node, bitstring, dict) {
29+
if (!node.left && !node.right) {
30+
dict[node.key] = bitstring;
31+
} else {
32+
if (node.left) {
33+
recurse(node.left, bitstring + "0", dict);
34+
}
35+
36+
if (node.right) {
37+
recurse(node.right, bitstring + "1", dict);
38+
}
39+
}
40+
return dict;
41+
}(tree, "", {});
42+
}
43+
}
44+
45+
function decode(bitstring, tree) {
46+
const result = [];
47+
let node = tree;
48+
49+
for (const bit of [...bitstring]) {
50+
node = bit === "0" ? node.left : node.right;
51+
if (!node.left && !node.right) {
52+
result.push(node.key);
53+
node = tree;
54+
}
55+
}
56+
57+
return result.join("");
58+
}
59+
60+
// This queue implementation is horribly inefficient, but a proper, heap-based implementation would
61+
// be longer that the algorithm itself
62+
function makeQueue(iterable) {
63+
return {
64+
data: [...iterable].sort((a, b) => a.weight - b.weight),
65+
enqueue(value) {
66+
const target = this.data.findIndex(x => x.weight > value.weight);
67+
if (target === -1) {
68+
this.data.push(value);
69+
} else {
70+
this.data = [...this.data.slice(0, target), value, ...this.data.slice(target)];
71+
}
72+
},
73+
dequeue() {
74+
const [result] = this.data.splice(0, 1);
75+
return result;
76+
}
77+
};
78+
}
79+
80+
const encoded = encode("Hello, World!");
81+
const decoded = decode(encoded.string, encoded.tree);
82+
console.log(encoded.string);
83+
console.log(decoded);
84+

chapters/data_compression/huffman/huffman.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ Program.cs
8181
{% sample lang="py" %}
8282
### Python
8383
[import, lang:"python"](code/python/huffman.py)
84+
{% sample lang="js" %}
85+
### JavaScript
86+
[import, lang:"javascript"](code/javascript/huffman.js)
8487
{% endmethod %}
8588

8689

0 commit comments

Comments
 (0)