Skip to content
Prev Previous commit
Next Next commit
Compression: Huffman coding using Heaps
  • Loading branch information
aladin002dz committed Oct 15, 2023
commit f951e51250a26c733c555e772580e733937075a4
File renamed without changes.
90 changes: 90 additions & 0 deletions Compression/HuffmanHeap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { BinaryHeap, minHeapComparator } from '../Data-Structures/Heap/BinaryHeap';
class Node {
constructor(symbol, frequency, left = null, right = null) {
this.symbol = symbol;
this.frequency = frequency;
this.left = left;
this.right = right;
}
}

class HuffmanCoder {
constructor(data) {
this.data = data;
this.codes = {};
this.buildHuffmanTree();
this.generateCodes(this.huffmanTree, "");
}

buildFrequencyTable() {
const frequencyTable = {};
for (const char of this.data) {
if (char in frequencyTable) {
frequencyTable[char]++;
} else {
frequencyTable[char] = 1;
}
}
return frequencyTable;
}

buildHuffmanTree() {
const frequencyTable = this.buildFrequencyTable();
const minHeap = new BinaryHeap(minHeapComparator);

for (const symbol in frequencyTable) {
minHeap.insert(new Node(symbol, frequencyTable[symbol]));
}

while (minHeap.size() > 1) {
const left = minHeap.extractTop();
const right = minHeap.extractTop();
const combined = new Node(null, left.frequency + right.frequency, left, right);
minHeap.insert(combined);
}

this.huffmanTree = minHeap.extractTop();
}

generateCodes(node, code) {
if (!node) return;

if (node.symbol) {
this.codes[node.symbol] = code;
} else {
this.generateCodes(node.left, code + "0");
this.generateCodes(node.right, code + "1");
}
}

encode(data) {
let encodedString = "";
for (const char of data) {
encodedString += this.codes[char];
}
return encodedString;
}

decode(encodedString) {
let decodedString = "";
let currentNode = this.huffmanTree;

for (const bit of encodedString) {
if (bit === "0") {
currentNode = currentNode.left;
} else {
currentNode = currentNode.right;
}

if (currentNode.symbol) {
decodedString += currentNode.symbol;
currentNode = this.huffmanTree;
}
}

return decodedString;
}
}


export { HuffmanCoder };
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
encodeHuffman,
decodeHuffman,
buildFrequencyTable
} from '../Huffman'
} from '../HuffmanArray'

describe('Huffman Coding', () => {
let data, freqTable, root
Expand Down
19 changes: 19 additions & 0 deletions Compression/test/HuffmanHeap.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { HuffmanCoder } from '../HuffmanHeap';

describe('HuffmanCoder', () => {
it('should encode and decode a simple string', () => {
const data = 'hello world';
const coder = new HuffmanCoder(data);
const encodedString = coder.encode(data);
const decodedString = coder.decode(encodedString);
expect(decodedString).toEqual(data);
});

it('should encode and decode a string with repeating characters', () => {
const data = 'aaaaabbbbcccdeeeee';
const coder = new HuffmanCoder(data);
const encodedString = coder.encode(data);
const decodedString = coder.decode(encodedString);
expect(decodedString).toEqual(data);
});
});