From 90f19824572da1f7355b05b7481e489094470aa1 Mon Sep 17 00:00:00 2001 From: aladin002dz Date: Wed, 11 Oct 2023 16:09:32 +0100 Subject: [PATCH 1/8] Huffman Compression Algorithm --- Compression/Huffman.js | 88 ++++++++++++++++++++++++++++++++ Compression/test/Huffman.test.js | 29 +++++++++++ 2 files changed, 117 insertions(+) create mode 100644 Compression/Huffman.js create mode 100644 Compression/test/Huffman.test.js diff --git a/Compression/Huffman.js b/Compression/Huffman.js new file mode 100644 index 0000000000..a1b53a449d --- /dev/null +++ b/Compression/Huffman.js @@ -0,0 +1,88 @@ +class HuffmanNode { + constructor(char, freq) { + this.char = char; + this.freq = freq; + this.left = null; + this.right = null; + } +} + +function buildHuffmanTree(freqTable) { + const nodes = Object.keys(freqTable).map((char) => new HuffmanNode(char, freqTable[char])); + + while (nodes.length > 1) { + nodes.sort((a, b) => a.freq - b.freq); + const left = nodes.shift(); + const right = nodes.shift(); + const parent = new HuffmanNode(null, left.freq + right.freq); + parent.left = left; + parent.right = right; + nodes.push(parent); + } + + return nodes[0]; +} + +function buildHuffmanCodes(root, prefix = '', codes = {}) { + if (root) { + if (root.char) { + codes[root.char] = prefix; + } + buildHuffmanCodes(root.left, prefix + '0', codes); + buildHuffmanCodes(root.right, prefix + '1', codes); + } + return codes; +} + +function encodeHuffman(data, freqTable) { + const root = buildHuffmanTree(freqTable); + const codes = buildHuffmanCodes(root); + + let encodedData = ''; + for (let char of data) { + encodedData += codes[char]; + } + + return encodedData; +} + +function decodeHuffman(encodedData, root) { + let decodedData = ''; + let currentNode = root; + for (let bit of encodedData) { + if (bit === '0') { + currentNode = currentNode.left; + } else { + currentNode = currentNode.right; + } + + if (currentNode.char) { + decodedData += currentNode.char; + currentNode = root; + } + } + + return decodedData; +} + +function buildFrequencyTable(data) { + const freqTable = {}; + + for (const char of data) { + freqTable[char] = (freqTable[char] || 0) + 1; + } + + return freqTable; +} + +// Example usage +const data = 'this is an example for huffman encoding'; +const freqTable = buildFrequencyTable(data); +const root = buildHuffmanTree(freqTable); +const encodedData = encodeHuffman(data, freqTable); +console.log('Encoded Data:', encodedData); + +const decodedData = decodeHuffman(encodedData, root); +console.log('Decoded Data:', decodedData); + +export { buildHuffmanCodes, buildHuffmanTree, encodeHuffman, decodeHuffman, buildFrequencyTable }; diff --git a/Compression/test/Huffman.test.js b/Compression/test/Huffman.test.js new file mode 100644 index 0000000000..255dbbedcd --- /dev/null +++ b/Compression/test/Huffman.test.js @@ -0,0 +1,29 @@ +import { buildHuffmanCodes, buildHuffmanTree, encodeHuffman, decodeHuffman, buildFrequencyTable } from '../Huffman'; + +describe('Huffman Coding', () => { + let data, freqTable, root; + + beforeEach(() => { + data = 'this is an example for huffman encoding'; + freqTable = buildFrequencyTable(data); + root = buildHuffmanTree(freqTable); + }); + + it('should encode and decode a string correctly', () => { + const encodedData = encodeHuffman(data, freqTable); + const decodedData = decodeHuffman(encodedData, root); + + expect(decodedData).toEqual(data); + }); + + it('should build Huffman codes correctly', () => { + const codes = buildHuffmanCodes(root); + + expect(codes['t']).toEqual('01010'); + expect(codes['h']).toEqual('11111'); + expect(codes['i']).toEqual('1001'); + expect(codes['s']).toEqual('0010'); + }); + + +}); From 4e87b220bc39bed409161ac5f514a077848c7765 Mon Sep 17 00:00:00 2001 From: aladin002dz Date: Wed, 11 Oct 2023 16:27:47 +0100 Subject: [PATCH 2/8] Huffman Compression Algorithm Comments --- Compression/Huffman.js | 236 +++++++++++------- Compression/test/Huffman.test.js | 62 ++--- Data-Structures/Heap/test/BinaryHeap.test.js | 2 +- Data-Structures/Stack/EvaluateExpression.js | 40 +-- .../Stack/test/EvaluateExpression.test.js | 29 ++- Maths/test/Determinant.test.js | 9 +- 6 files changed, 219 insertions(+), 159 deletions(-) diff --git a/Compression/Huffman.js b/Compression/Huffman.js index a1b53a449d..180522b051 100644 --- a/Compression/Huffman.js +++ b/Compression/Huffman.js @@ -1,88 +1,148 @@ -class HuffmanNode { - constructor(char, freq) { - this.char = char; - this.freq = freq; - this.left = null; - this.right = null; - } -} - -function buildHuffmanTree(freqTable) { - const nodes = Object.keys(freqTable).map((char) => new HuffmanNode(char, freqTable[char])); - - while (nodes.length > 1) { - nodes.sort((a, b) => a.freq - b.freq); - const left = nodes.shift(); - const right = nodes.shift(); - const parent = new HuffmanNode(null, left.freq + right.freq); - parent.left = left; - parent.right = right; - nodes.push(parent); - } - - return nodes[0]; -} - -function buildHuffmanCodes(root, prefix = '', codes = {}) { - if (root) { - if (root.char) { - codes[root.char] = prefix; - } - buildHuffmanCodes(root.left, prefix + '0', codes); - buildHuffmanCodes(root.right, prefix + '1', codes); - } - return codes; -} - -function encodeHuffman(data, freqTable) { - const root = buildHuffmanTree(freqTable); - const codes = buildHuffmanCodes(root); - - let encodedData = ''; - for (let char of data) { - encodedData += codes[char]; - } - - return encodedData; -} - -function decodeHuffman(encodedData, root) { - let decodedData = ''; - let currentNode = root; - for (let bit of encodedData) { - if (bit === '0') { - currentNode = currentNode.left; - } else { - currentNode = currentNode.right; - } - - if (currentNode.char) { - decodedData += currentNode.char; - currentNode = root; - } - } - - return decodedData; -} - -function buildFrequencyTable(data) { - const freqTable = {}; - - for (const char of data) { - freqTable[char] = (freqTable[char] || 0) + 1; - } - - return freqTable; -} - -// Example usage -const data = 'this is an example for huffman encoding'; -const freqTable = buildFrequencyTable(data); -const root = buildHuffmanTree(freqTable); -const encodedData = encodeHuffman(data, freqTable); -console.log('Encoded Data:', encodedData); - -const decodedData = decodeHuffman(encodedData, root); -console.log('Decoded Data:', decodedData); - -export { buildHuffmanCodes, buildHuffmanTree, encodeHuffman, decodeHuffman, buildFrequencyTable }; + +/** + * Huffman Coding is a lossless data compression algorithm that uses variable-length codes to represent characters. + * + * The algorithm works by assigning shorter codes to characters that occur more frequently. This results in a compressed representation of the data. + * + * Huffman Coding is widely used in a variety of applications, including file compression, data transmission, and image processing. + * + * More information on Huffman Coding can be found here: https://en.wikipedia.org/wiki/Huffman_coding + */ + +/** + * Builds a frequency table from a string. + * @example + * buildFrequencyTable('this is an example for huffman encoding') + * returns { ' ': 6, a: 2, c: 1, d: 1, e: 4, f: 3, g: 1, h: 2, i: 3, l: 1, m: 1, n: 4, o: 1, p: 1, r: 1, s: 2, t: 2, u: 1, x: 1 } + * @param {string} data - The string to build the frequency table from. + * @returns {Object} - The frequency table. + */ +function buildFrequencyTable(data) { + const freqTable = {} + + for (const char of data) { + freqTable[char] = (freqTable[char] || 0) + 1 + } + + return freqTable +} + + +/** + * A Huffman Node is a node in a Huffman tree. + * @class HuffmanNode + * @property {string} char - The character represented by the node. + * @property {number} freq - The frequency of the character. + * @property {HuffmanNode} left - The left child of the node. + * @property {HuffmanNode} right - The right child of the node. + */ +class HuffmanNode { + constructor(char, freq) { + this.char = char + this.freq = freq + this.left = null + this.right = null + } +} + +/** + * Builds a Huffman tree from a frequency table. + * @param {Object} freqTable - The frequency table to use for building the tree. + * @returns {HuffmanNode} - The root node of the Huffman tree. + */ +function buildHuffmanTree(freqTable) { + const nodes = Object.keys(freqTable).map( + (char) => new HuffmanNode(char, freqTable[char]) + ) + + while (nodes.length > 1) { + nodes.sort((a, b) => a.freq - b.freq) + const left = nodes.shift() + const right = nodes.shift() + const parent = new HuffmanNode(null, left.freq + right.freq) + parent.left = left + parent.right = right + nodes.push(parent) + } + + return nodes[0] +} + +/** + * Builds a Huffman code table from a Huffman tree. + * @param {HuffmanNode} root - The root node of the Huffman tree. + * @param {string} [prefix=''] - The prefix to use for the Huffman codes. + * @param {Object} [codes={}] - The Huffman code table. + * @returns {Object} - The Huffman code table. + */ +function buildHuffmanCodes(root, prefix = '', codes = {}) { + if (root) { + if (root.char) { + codes[root.char] = prefix + } + buildHuffmanCodes(root.left, prefix + '0', codes) + buildHuffmanCodes(root.right, prefix + '1', codes) + } + return codes +} + +/** + * Encodes a string using Huffman Coding. + * @param {string} data - The string to encode. + * @param {Object} freqTable - The frequency table to use for encoding. + * @returns {string} - The encoded string. + */ +function encodeHuffman(data, freqTable) { + const root = buildHuffmanTree(freqTable) + const codes = buildHuffmanCodes(root) + + let encodedData = '' + for (let char of data) { + encodedData += codes[char] + } + + return encodedData +} + +/** + * Decodes a string using Huffman Coding. + * @param {string} encodedData - The string to decode. + * @param {HuffmanNode} root - The root node of the Huffman tree. + * @returns {string} - The decoded string. + */ +function decodeHuffman(encodedData, root) { + let decodedData = '' + let currentNode = root + for (let bit of encodedData) { + if (bit === '0') { + currentNode = currentNode.left + } else { + currentNode = currentNode.right + } + + if (currentNode.char) { + decodedData += currentNode.char + currentNode = root + } + } + + return decodedData +} + +// Example usage +const data = 'this is an example for huffman encoding' +const freqTable = buildFrequencyTable(data) +const root = buildHuffmanTree(freqTable) +const encodedData = encodeHuffman(data, freqTable) +console.log('Encoded Data:', encodedData) + +const decodedData = decodeHuffman(encodedData, root) +console.log('Decoded Data:', decodedData) + +export { + buildHuffmanCodes, + buildHuffmanTree, + encodeHuffman, + decodeHuffman, + buildFrequencyTable +} diff --git a/Compression/test/Huffman.test.js b/Compression/test/Huffman.test.js index 255dbbedcd..358e0ed5ea 100644 --- a/Compression/test/Huffman.test.js +++ b/Compression/test/Huffman.test.js @@ -1,29 +1,33 @@ -import { buildHuffmanCodes, buildHuffmanTree, encodeHuffman, decodeHuffman, buildFrequencyTable } from '../Huffman'; - -describe('Huffman Coding', () => { - let data, freqTable, root; - - beforeEach(() => { - data = 'this is an example for huffman encoding'; - freqTable = buildFrequencyTable(data); - root = buildHuffmanTree(freqTable); - }); - - it('should encode and decode a string correctly', () => { - const encodedData = encodeHuffman(data, freqTable); - const decodedData = decodeHuffman(encodedData, root); - - expect(decodedData).toEqual(data); - }); - - it('should build Huffman codes correctly', () => { - const codes = buildHuffmanCodes(root); - - expect(codes['t']).toEqual('01010'); - expect(codes['h']).toEqual('11111'); - expect(codes['i']).toEqual('1001'); - expect(codes['s']).toEqual('0010'); - }); - - -}); +import { + buildHuffmanCodes, + buildHuffmanTree, + encodeHuffman, + decodeHuffman, + buildFrequencyTable +} from '../Huffman' + +describe('Huffman Coding', () => { + let data, freqTable, root + + beforeEach(() => { + data = 'this is an example for huffman encoding' + freqTable = buildFrequencyTable(data) + root = buildHuffmanTree(freqTable) + }) + + it('should encode and decode a string correctly', () => { + const encodedData = encodeHuffman(data, freqTable) + const decodedData = decodeHuffman(encodedData, root) + + expect(decodedData).toEqual(data) + }) + + it('should build Huffman codes correctly', () => { + const codes = buildHuffmanCodes(root) + + expect(codes['t']).toEqual('01010') + expect(codes['h']).toEqual('11111') + expect(codes['i']).toEqual('1001') + expect(codes['s']).toEqual('0010') + }) +}) diff --git a/Data-Structures/Heap/test/BinaryHeap.test.js b/Data-Structures/Heap/test/BinaryHeap.test.js index 56aef11e02..aef538d9fa 100644 --- a/Data-Structures/Heap/test/BinaryHeap.test.js +++ b/Data-Structures/Heap/test/BinaryHeap.test.js @@ -36,7 +36,7 @@ describe('BinaryHeap', () => { it('should handle insertion of duplicate values', () => { // Check if the heap handles duplicate values correctly minHeap.insert(2) - console.log(minHeap.heap); + console.log(minHeap.heap) expect(minHeap.heap).toEqual([1, 3, 2, 4, 8, 6, 2]) }) diff --git a/Data-Structures/Stack/EvaluateExpression.js b/Data-Structures/Stack/EvaluateExpression.js index e59a4a37c0..f8e976e16e 100644 --- a/Data-Structures/Stack/EvaluateExpression.js +++ b/Data-Structures/Stack/EvaluateExpression.js @@ -6,53 +6,53 @@ * @returns {number|null} - Result of the expression evaluation, or null if the expression is invalid. */ function evaluatePostfixExpression(expression) { - const stack = []; + const stack = [] // Helper function to perform an operation and push the result to the stack. Returns success. function performOperation(operator) { - const rightOp = stack.pop(); // Right operand is the top of the stack - const leftOp = stack.pop(); // Left operand is the next item on the stack + const rightOp = stack.pop() // Right operand is the top of the stack + const leftOp = stack.pop() // Left operand is the next item on the stack if (leftOp === undefined || rightOp === undefined) { - return false; // Invalid expression + return false // Invalid expression } switch (operator) { case '+': - stack.push(leftOp + rightOp); - break; + stack.push(leftOp + rightOp) + break case '-': - stack.push(leftOp - rightOp); - break; + stack.push(leftOp - rightOp) + break case '*': - stack.push(leftOp * rightOp); - break; + stack.push(leftOp * rightOp) + break case '/': if (rightOp === 0) { - return false; + return false } - stack.push(leftOp / rightOp); - break; + stack.push(leftOp / rightOp) + break default: - return false; // Unknown operator + return false // Unknown operator } - return true; + return true } - const tokens = expression.split(/\s+/); + const tokens = expression.split(/\s+/) for (const token of tokens) { if (!isNaN(parseFloat(token))) { // If the token is a number, push it to the stack - stack.push(parseFloat(token)); + stack.push(parseFloat(token)) } else { // If the token is an operator, perform the operation if (!performOperation(token)) { - return null; // Invalid expression + return null // Invalid expression } } } - return (stack.length === 1) ? stack[0] : null; + return stack.length === 1 ? stack[0] : null } -export { evaluatePostfixExpression }; +export { evaluatePostfixExpression } diff --git a/Data-Structures/Stack/test/EvaluateExpression.test.js b/Data-Structures/Stack/test/EvaluateExpression.test.js index eea764cac2..69a2e16365 100644 --- a/Data-Structures/Stack/test/EvaluateExpression.test.js +++ b/Data-Structures/Stack/test/EvaluateExpression.test.js @@ -1,22 +1,21 @@ -import { evaluatePostfixExpression } from '../EvaluateExpression.js'; +import { evaluatePostfixExpression } from '../EvaluateExpression.js' describe('evaluatePostfixExpression', () => { it('should evaluate a valid expression', () => { - const expression = '3 4 * 2 / 5 +'; // (3 * 4) / 2 + 5 = 11 - const result = evaluatePostfixExpression(expression); - expect(result).toBe(11); - }); + const expression = '3 4 * 2 / 5 +' // (3 * 4) / 2 + 5 = 11 + const result = evaluatePostfixExpression(expression) + expect(result).toBe(11) + }) it('should handle division by zero', () => { - const expression = '3 0 /'; // Division by zero - const result = evaluatePostfixExpression(expression); - expect(result).toBe(null); - }); + const expression = '3 0 /' // Division by zero + const result = evaluatePostfixExpression(expression) + expect(result).toBe(null) + }) it('should handle an invalid expression', () => { - const expression = '3 * 4 2 / +'; // Invalid expression - const result = evaluatePostfixExpression(expression); - expect(result).toBe(null); - }); - -}); + const expression = '3 * 4 2 / +' // Invalid expression + const result = evaluatePostfixExpression(expression) + expect(result).toBe(null) + }) +}) diff --git a/Maths/test/Determinant.test.js b/Maths/test/Determinant.test.js index df9d34df83..f6cba8241c 100644 --- a/Maths/test/Determinant.test.js +++ b/Maths/test/Determinant.test.js @@ -54,10 +54,7 @@ describe('Determinant', () => { 'Square matrix is required.' ], [[1, 3, 2, [5, 8, 6], 3], 'Input is not a valid 2D matrix.'] - ])( - 'Should return the error message.', - (matrix, expected) => { - expect(() => determinant(matrix)).toThrowError(expected) - } - ) + ])('Should return the error message.', (matrix, expected) => { + expect(() => determinant(matrix)).toThrowError(expected) + }) }) From c4e98aa0232bb5461352a74f83bc2f85d2d5bda9 Mon Sep 17 00:00:00 2001 From: aladin002dz Date: Wed, 11 Oct 2023 16:33:22 +0100 Subject: [PATCH 3/8] Huffman Compression Algorithm Comments --- Compression/Huffman.js | 122 ++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 62 deletions(-) diff --git a/Compression/Huffman.js b/Compression/Huffman.js index 180522b051..19ce40e5b1 100644 --- a/Compression/Huffman.js +++ b/Compression/Huffman.js @@ -1,4 +1,3 @@ - /** * Huffman Coding is a lossless data compression algorithm that uses variable-length codes to represent characters. * @@ -18,16 +17,15 @@ * @returns {Object} - The frequency table. */ function buildFrequencyTable(data) { - const freqTable = {} + const freqTable = {} - for (const char of data) { - freqTable[char] = (freqTable[char] || 0) + 1 - } + for (const char of data) { + freqTable[char] = (freqTable[char] || 0) + 1 + } - return freqTable + return freqTable } - /** * A Huffman Node is a node in a Huffman tree. * @class HuffmanNode @@ -37,35 +35,35 @@ function buildFrequencyTable(data) { * @property {HuffmanNode} right - The right child of the node. */ class HuffmanNode { - constructor(char, freq) { - this.char = char - this.freq = freq - this.left = null - this.right = null - } + constructor(char, freq) { + this.char = char + this.freq = freq + this.left = null + this.right = null + } } /** - * Builds a Huffman tree from a frequency table. + * Builds a Huffman tree from a frequency table. * @param {Object} freqTable - The frequency table to use for building the tree. * @returns {HuffmanNode} - The root node of the Huffman tree. */ function buildHuffmanTree(freqTable) { - const nodes = Object.keys(freqTable).map( - (char) => new HuffmanNode(char, freqTable[char]) - ) - - while (nodes.length > 1) { - nodes.sort((a, b) => a.freq - b.freq) - const left = nodes.shift() - const right = nodes.shift() - const parent = new HuffmanNode(null, left.freq + right.freq) - parent.left = left - parent.right = right - nodes.push(parent) - } - - return nodes[0] + const nodes = Object.keys(freqTable).map( + (char) => new HuffmanNode(char, freqTable[char]) + ) + + while (nodes.length > 1) { + nodes.sort((a, b) => a.freq - b.freq) + const left = nodes.shift() + const right = nodes.shift() + const parent = new HuffmanNode(null, left.freq + right.freq) + parent.left = left + parent.right = right + nodes.push(parent) + } + + return nodes[0] } /** @@ -76,14 +74,14 @@ function buildHuffmanTree(freqTable) { * @returns {Object} - The Huffman code table. */ function buildHuffmanCodes(root, prefix = '', codes = {}) { - if (root) { - if (root.char) { - codes[root.char] = prefix - } - buildHuffmanCodes(root.left, prefix + '0', codes) - buildHuffmanCodes(root.right, prefix + '1', codes) + if (root) { + if (root.char) { + codes[root.char] = prefix } - return codes + buildHuffmanCodes(root.left, prefix + '0', codes) + buildHuffmanCodes(root.right, prefix + '1', codes) + } + return codes } /** @@ -93,15 +91,15 @@ function buildHuffmanCodes(root, prefix = '', codes = {}) { * @returns {string} - The encoded string. */ function encodeHuffman(data, freqTable) { - const root = buildHuffmanTree(freqTable) - const codes = buildHuffmanCodes(root) + const root = buildHuffmanTree(freqTable) + const codes = buildHuffmanCodes(root) - let encodedData = '' - for (let char of data) { - encodedData += codes[char] - } + let encodedData = '' + for (let char of data) { + encodedData += codes[char] + } - return encodedData + return encodedData } /** @@ -111,22 +109,22 @@ function encodeHuffman(data, freqTable) { * @returns {string} - The decoded string. */ function decodeHuffman(encodedData, root) { - let decodedData = '' - let currentNode = root - for (let bit of encodedData) { - if (bit === '0') { - currentNode = currentNode.left - } else { - currentNode = currentNode.right - } - - if (currentNode.char) { - decodedData += currentNode.char - currentNode = root - } + let decodedData = '' + let currentNode = root + for (let bit of encodedData) { + if (bit === '0') { + currentNode = currentNode.left + } else { + currentNode = currentNode.right + } + + if (currentNode.char) { + decodedData += currentNode.char + currentNode = root } + } - return decodedData + return decodedData } // Example usage @@ -140,9 +138,9 @@ const decodedData = decodeHuffman(encodedData, root) console.log('Decoded Data:', decodedData) export { - buildHuffmanCodes, - buildHuffmanTree, - encodeHuffman, - decodeHuffman, - buildFrequencyTable + buildHuffmanCodes, + buildHuffmanTree, + encodeHuffman, + decodeHuffman, + buildFrequencyTable } From bd83db999a319cf22d4553a832d0ee8cb77dfaf0 Mon Sep 17 00:00:00 2001 From: aladin002dz Date: Thu, 12 Oct 2023 11:33:42 +0100 Subject: [PATCH 4/8] Compression Huffman: Optimize algorithm --- Compression/Huffman.js | 17 ++++------------- Compression/test/Huffman.test.js | 13 +++++++++---- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/Compression/Huffman.js b/Compression/Huffman.js index 19ce40e5b1..8cfb856914 100644 --- a/Compression/Huffman.js +++ b/Compression/Huffman.js @@ -53,10 +53,11 @@ function buildHuffmanTree(freqTable) { (char) => new HuffmanNode(char, freqTable[char]) ) + while (nodes.length > 1) { - nodes.sort((a, b) => a.freq - b.freq) - const left = nodes.shift() - const right = nodes.shift() + nodes.sort((a, b) => b.freq - a.freq) + const right = nodes.pop() + const left = nodes.pop() const parent = new HuffmanNode(null, left.freq + right.freq) parent.left = left parent.right = right @@ -127,16 +128,6 @@ function decodeHuffman(encodedData, root) { return decodedData } -// Example usage -const data = 'this is an example for huffman encoding' -const freqTable = buildFrequencyTable(data) -const root = buildHuffmanTree(freqTable) -const encodedData = encodeHuffman(data, freqTable) -console.log('Encoded Data:', encodedData) - -const decodedData = decodeHuffman(encodedData, root) -console.log('Decoded Data:', decodedData) - export { buildHuffmanCodes, buildHuffmanTree, diff --git a/Compression/test/Huffman.test.js b/Compression/test/Huffman.test.js index 358e0ed5ea..1fd8917087 100644 --- a/Compression/test/Huffman.test.js +++ b/Compression/test/Huffman.test.js @@ -25,9 +25,14 @@ describe('Huffman Coding', () => { it('should build Huffman codes correctly', () => { const codes = buildHuffmanCodes(root) - expect(codes['t']).toEqual('01010') - expect(codes['h']).toEqual('11111') - expect(codes['i']).toEqual('1001') - expect(codes['s']).toEqual('0010') + console.log(codes['t']) + console.log(codes['h']) + console.log(codes['i']) + console.log(codes['s']) + + expect(codes['t']).toEqual('01101') + expect(codes['h']).toEqual('0111') + expect(codes['i']).toEqual('0100') + expect(codes['s']).toEqual('1010') }) }) From b02eae876f3396627e6b44f942866fb282937a46 Mon Sep 17 00:00:00 2001 From: aladin002dz Date: Thu, 12 Oct 2023 11:37:26 +0100 Subject: [PATCH 5/8] Compression Huffman: prettier --- Compression/Huffman.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Compression/Huffman.js b/Compression/Huffman.js index 8cfb856914..88ca04ee5e 100644 --- a/Compression/Huffman.js +++ b/Compression/Huffman.js @@ -53,7 +53,6 @@ function buildHuffmanTree(freqTable) { (char) => new HuffmanNode(char, freqTable[char]) ) - while (nodes.length > 1) { nodes.sort((a, b) => b.freq - a.freq) const right = nodes.pop() From f951e51250a26c733c555e772580e733937075a4 Mon Sep 17 00:00:00 2001 From: aladin002dz Date: Sun, 15 Oct 2023 14:52:23 +0100 Subject: [PATCH 6/8] Compression: Huffman coding using Heaps --- Compression/{Huffman.js => HuffmanArray.js} | 0 Compression/HuffmanHeap.js | 90 +++++++++++++++++++ .../{Huffman.test.js => HuffmanArray.test.js} | 2 +- Compression/test/HuffmanHeap.test.js | 19 ++++ 4 files changed, 110 insertions(+), 1 deletion(-) rename Compression/{Huffman.js => HuffmanArray.js} (100%) create mode 100644 Compression/HuffmanHeap.js rename Compression/test/{Huffman.test.js => HuffmanArray.test.js} (97%) create mode 100644 Compression/test/HuffmanHeap.test.js diff --git a/Compression/Huffman.js b/Compression/HuffmanArray.js similarity index 100% rename from Compression/Huffman.js rename to Compression/HuffmanArray.js diff --git a/Compression/HuffmanHeap.js b/Compression/HuffmanHeap.js new file mode 100644 index 0000000000..b6a9ffddf6 --- /dev/null +++ b/Compression/HuffmanHeap.js @@ -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 }; diff --git a/Compression/test/Huffman.test.js b/Compression/test/HuffmanArray.test.js similarity index 97% rename from Compression/test/Huffman.test.js rename to Compression/test/HuffmanArray.test.js index 1fd8917087..a5f8c6bbb9 100644 --- a/Compression/test/Huffman.test.js +++ b/Compression/test/HuffmanArray.test.js @@ -4,7 +4,7 @@ import { encodeHuffman, decodeHuffman, buildFrequencyTable -} from '../Huffman' +} from '../HuffmanArray' describe('Huffman Coding', () => { let data, freqTable, root diff --git a/Compression/test/HuffmanHeap.test.js b/Compression/test/HuffmanHeap.test.js new file mode 100644 index 0000000000..947f9c8773 --- /dev/null +++ b/Compression/test/HuffmanHeap.test.js @@ -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); + }); +}); \ No newline at end of file From 85df9122e0c0b19acafdd144f4073be303ff415c Mon Sep 17 00:00:00 2001 From: aladin002dz Date: Sun, 15 Oct 2023 14:56:08 +0100 Subject: [PATCH 7/8] Prettier Style --- Compression/HuffmanHeap.js | 187 ++++++++++++++------------- Compression/test/HuffmanHeap.test.js | 38 +++--- 2 files changed, 116 insertions(+), 109 deletions(-) diff --git a/Compression/HuffmanHeap.js b/Compression/HuffmanHeap.js index b6a9ffddf6..e314c57d6f 100644 --- a/Compression/HuffmanHeap.js +++ b/Compression/HuffmanHeap.js @@ -1,90 +1,97 @@ -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 }; +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 } diff --git a/Compression/test/HuffmanHeap.test.js b/Compression/test/HuffmanHeap.test.js index 947f9c8773..870c217476 100644 --- a/Compression/test/HuffmanHeap.test.js +++ b/Compression/test/HuffmanHeap.test.js @@ -1,19 +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); - }); -}); \ No newline at end of file +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) + }) +}) From b583f2e91ef9ec7bd3662e2ed2009bb40bc2aa2f Mon Sep 17 00:00:00 2001 From: aladin002dz Date: Sun, 15 Oct 2023 15:05:45 +0100 Subject: [PATCH 8/8] Compression; removing unecessary logging --- Compression/test/HuffmanArray.test.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Compression/test/HuffmanArray.test.js b/Compression/test/HuffmanArray.test.js index a5f8c6bbb9..bc79210c3c 100644 --- a/Compression/test/HuffmanArray.test.js +++ b/Compression/test/HuffmanArray.test.js @@ -25,11 +25,6 @@ describe('Huffman Coding', () => { it('should build Huffman codes correctly', () => { const codes = buildHuffmanCodes(root) - console.log(codes['t']) - console.log(codes['h']) - console.log(codes['i']) - console.log(codes['s']) - expect(codes['t']).toEqual('01101') expect(codes['h']).toEqual('0111') expect(codes['i']).toEqual('0100')