-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathhuffman.js
More file actions
109 lines (90 loc) · 3.16 KB
/
huffman.js
File metadata and controls
109 lines (90 loc) · 3.16 KB
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/**
* 霍夫曼编码实现 - JavaScript
* 基于贪心策略构建最优前缀编码树
*/
// 霍夫曼树节点
class HuffmanNode {
constructor(char, freq, left = null, right = null) {
this.char = char; // 字符(叶子节点)
this.freq = freq; // 频率
this.left = left; // 左子树(编码0)
this.right = right; // 右子树(编码1)
}
}
class HuffmanCoding {
// 生成霍夫曼编码表
static huffmanEncode(text) {
// 统计字符频率
const frequency = {};
for (const char of text) {
frequency[char] = (frequency[char] || 0) + 1;
}
// 初始化:所有字符节点入队
const queue = [];
for (const [char, freq] of Object.entries(frequency)) {
queue.push(new HuffmanNode(char, freq));
}
queue.sort((a, b) => a.freq - b.freq);
// 循环合并最小频率节点,构建霍夫曼树
while (queue.length > 1) {
const left = queue.shift(); // 最小
const right = queue.shift(); // 次小
const parent = new HuffmanNode(null, left.freq + right.freq, left, right);
// 保持队列有序
let inserted = false;
for (let i = 0; i < queue.length; i++) {
if (queue[i].freq >= parent.freq) {
queue.splice(i, 0, parent);
inserted = true;
break;
}
}
if (!inserted) {
queue.push(parent);
}
}
// 生成编码表
const encodingMap = {};
const root = queue[0];
this.generateCodes(root, "", encodingMap);
return encodingMap;
}
// 递归生成编码:左0右1
static generateCodes(node, code, encodingMap) {
if (!node) return;
// 叶子节点:存储编码
if (!node.left && !node.right) {
encodingMap[node.char] = code || '0';
return;
}
this.generateCodes(node.left, code + '0', encodingMap);
this.generateCodes(node.right, code + '1', encodingMap);
}
static compress(text, encodingMap) {
let compressed = "";
for (const char of text) {
compressed += encodingMap[char];
}
return compressed;
}
static decompress(compressed, root) {
let decompressed = "";
let current = root;
for (const bit of compressed) {
current = bit === '0' ? current.left : current.right;
if (!current.left && !current.right) {
decompressed += current.char;
current = root;
}
}
return decompressed;
}
}
// 示例使用
const text = "hello world";
console.log("原始文本:", text);
const encodingMap = HuffmanCoding.huffmanEncode(text);
console.log("编码表:", encodingMap);
const compressed = HuffmanCoding.compress(text, encodingMap);
console.log("压缩后:", compressed);
console.log("压缩率:", compressed.length / (text.length * 8));