From c6177ffeb9ba13b413503cef07a3dc1c634fb437 Mon Sep 17 00:00:00 2001 From: Revone Date: Sun, 15 Oct 2023 22:25:42 +0800 Subject: [PATCH] [heap, priority queue] Redesigned tested pass --- test/unit/data-structures/heap/heap.test.ts | 44 ++++--- .../data-structures/heap/max-heap.test.ts | 84 +++++++------ .../data-structures/heap/min-heap.test.ts | 110 +++++++----------- .../priority-queue/max-priority-queue.test.ts | 16 ++- .../priority-queue/priority-queue.test.ts | 44 +++---- 5 files changed, 133 insertions(+), 165 deletions(-) diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index 06cb7a9..ac6f4f6 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -21,34 +21,42 @@ describe('Heap Operation Test', () => { }); it('should object heap work well', function () { - const minHeap = new MinHeap<{a: string}>(); - minHeap.add(1, {a: 'a1'}); - minHeap.add(6, {a: 'a6'}); - minHeap.add(2, {a: 'a2'}); - minHeap.add(0, {a: 'a0'}); + const minHeap = new MinHeap<{a: string; key: number}>((a, b) => a.key - b.key); + minHeap.add({key: 1, a: 'a1'}); + minHeap.add({key: 6, a: 'a6'}); + minHeap.add({key: 2, a: 'a2'}); + minHeap.add({key: 0, a: 'a0'}); - expect(minHeap.peek()).toEqual({a: 'a0'}); - expect(minHeap.toArray()).toEqual([{a: 'a0'}, {a: 'a1'}, {a: 'a2'}, {a: 'a6'}]); + expect(minHeap.peek()).toEqual({a: 'a0', key: 0}); + console.log('---', minHeap.toArray()); + expect(minHeap.toArray().map(item => ({a: item.a}))).toEqual([{a: 'a0'}, {a: 'a1'}, {a: 'a2'}, {a: 'a6'}]); let i = 0; const expectPolled = [{a: 'a0'}, {a: 'a1'}, {a: 'a2'}, {a: 'a6'}]; while (minHeap.size > 0) { - expect(minHeap.poll()).toEqual(expectPolled[i]); + expect({a: minHeap.poll()?.a}).toEqual(expectPolled[i]); i++; } - const maxHeap = new MaxHeap<{a: string}>(); - maxHeap.add(1, {a: 'a1'}); - maxHeap.add(6, {a: 'a6'}); - maxHeap.add(5, {a: 'a5'}); - maxHeap.add(2, {a: 'a2'}); - maxHeap.add(0, {a: 'a0'}); - maxHeap.add(9, {a: 'a9'}); - expect(maxHeap.peek()).toEqual({a: 'a9'}); - expect(maxHeap.toArray()).toEqual([{a: 'a9'}, {a: 'a2'}, {a: 'a6'}, {a: 'a1'}, {a: 'a0'}, {a: 'a5'}]); + const maxHeap = new MaxHeap<{key: number; a: string}>((a, b) => b.key - a.key); + maxHeap.add({key: 1, a: 'a1'}); + maxHeap.add({key: 6, a: 'a6'}); + maxHeap.add({key: 5, a: 'a5'}); + maxHeap.add({key: 2, a: 'a2'}); + maxHeap.add({key: 0, a: 'a0'}); + maxHeap.add({key: 9, a: 'a9'}); + expect(maxHeap.peek()).toEqual({a: 'a9', key: 9}); + expect(maxHeap.toArray().map(item => ({a: item.a}))).toEqual([ + {a: 'a9'}, + {a: 'a2'}, + {a: 'a6'}, + {a: 'a1'}, + {a: 'a0'}, + {a: 'a5'} + ]); const maxExpectPolled = [{a: 'a9'}, {a: 'a6'}, {a: 'a5'}, {a: 'a2'}, {a: 'a1'}, {a: 'a0'}]; let maxI = 0; while (maxHeap.size > 0) { - expect(maxHeap.poll()).toEqual(maxExpectPolled[maxI]); + expect({a: maxHeap.poll()?.a}).toEqual(maxExpectPolled[maxI]); maxI++; } }); diff --git a/test/unit/data-structures/heap/max-heap.test.ts b/test/unit/data-structures/heap/max-heap.test.ts index a2f3b50..6b120fb 100644 --- a/test/unit/data-structures/heap/max-heap.test.ts +++ b/test/unit/data-structures/heap/max-heap.test.ts @@ -1,44 +1,52 @@ -import {HeapItem, MaxHeap} from '../../../../src'; +import {CompareFunction, MaxHeap} from '../../../../src'; -describe('MaxHeap Operation Test', () => { - it('should object Max Heap operations be proper', function () { - const maxHeap = new MaxHeap<{keyA: string}>(); - const myObj1 = {keyA: 'a1'}, - myObj6 = {keyA: 'a6'}, - myObj5 = {keyA: 'a5'}, - myObj2 = {keyA: 'a2'}, - myObj0 = {keyA: 'a0'}, - myObj9 = {keyA: 'a9'}; - maxHeap.add(1, myObj1); - expect(maxHeap.has(myObj1)).toBe(true); - expect(maxHeap.has(myObj9)).toBe(false); - maxHeap.add(6, myObj6); - expect(maxHeap.has(myObj6)).toBe(true); - maxHeap.add(5, myObj5); - expect(maxHeap.has(myObj5)).toBe(true); - maxHeap.add(2, myObj2); - expect(maxHeap.has(myObj2)).toBe(true); - expect(maxHeap.has(myObj6)).toBe(true); - maxHeap.add(0, myObj0); - expect(maxHeap.has(myObj0)).toBe(true); - expect(maxHeap.has(myObj9)).toBe(false); - maxHeap.add(9, myObj9); - expect(maxHeap.has(myObj9)).toBe(true); +describe('MaxHeap', () => { + const numberComparator: CompareFunction = (a, b) => b - a; + let maxHeap: MaxHeap; - const peek9 = maxHeap.peek(true); - peek9 && peek9.val && expect(peek9.val.keyA).toBe('a9'); + beforeEach(() => { + maxHeap = new MaxHeap(numberComparator); + }); - const heapToArr = maxHeap.toArray(true); - expect(heapToArr.map(item => item?.val?.keyA)).toEqual(['a9', 'a2', 'a6', 'a1', 'a0', 'a5']); + test('add and poll elements in descending order', () => { + maxHeap.add(3); + maxHeap.add(1); + maxHeap.add(4); + maxHeap.add(2); - const values = ['a9', 'a6', 'a5', 'a2', 'a1', 'a0']; - let i = 0; - while (maxHeap.size > 0) { - const polled = maxHeap.poll(true); - expect(polled).toBeInstanceOf(HeapItem); - polled && expect(polled.val).toHaveProperty('keyA'); - polled && polled.val && expect(polled.val.keyA).toBe(values[i]); - i++; - } + expect(maxHeap.poll()).toBe(4); + expect(maxHeap.poll()).toBe(3); + expect(maxHeap.poll()).toBe(2); + expect(maxHeap.poll()).toBe(1); + }); + + test('peek at the top element without removing it', () => { + maxHeap.add(3); + maxHeap.add(1); + maxHeap.add(4); + maxHeap.add(2); + + expect(maxHeap.peek()).toBe(4); + expect(maxHeap.size).toBe(4); + }); + + test('sort elements in descending order', () => { + maxHeap.add(3); + maxHeap.add(1); + maxHeap.add(4); + maxHeap.add(2); + + const sortedArray = maxHeap.sort(); + expect(sortedArray).toEqual([4, 3, 2, 1]); + }); + + test('check if the heap is empty', () => { + expect(maxHeap.isEmpty()).toBe(true); + + maxHeap.add(5); + expect(maxHeap.isEmpty()).toBe(false); + + maxHeap.poll(); + expect(maxHeap.isEmpty()).toBe(true); }); }); diff --git a/test/unit/data-structures/heap/min-heap.test.ts b/test/unit/data-structures/heap/min-heap.test.ts index 4bef02d..14de30f 100644 --- a/test/unit/data-structures/heap/min-heap.test.ts +++ b/test/unit/data-structures/heap/min-heap.test.ts @@ -1,82 +1,52 @@ -import {HeapItem, MinHeap} from '../../../../src'; +import {CompareFunction, MinHeap} from '../../../../src'; -describe('MinHeap Operation Test', () => { - it('should numeric Min Heap operations be proper', function () { - const minNumHeap = new MinHeap(); - expect(minNumHeap).toBeInstanceOf(MinHeap); +describe('MinHeap', () => { + const numberComparator: CompareFunction = (a, b) => a - b; + let minHeap: MinHeap; - minNumHeap.add(1); - expect(minNumHeap.has(1)).toBe(true); - minNumHeap.add(6); - expect(minNumHeap.has(2)).toBe(false); - expect(minNumHeap.has(6)).toBe(true); - minNumHeap.add(2); - expect(minNumHeap.has(2)).toBe(true); - minNumHeap.add(0); - expect(minNumHeap.has(0)).toBe(true); - minNumHeap.add(5); - expect(minNumHeap.has(5)).toBe(true); - minNumHeap.add(9); - expect(minNumHeap.has(9)).toBe(true); - expect(minNumHeap.size).toBe(6); - - const poll1 = minNumHeap.poll(true); - expect(poll1).toBeInstanceOf(HeapItem); - poll1 instanceof HeapItem && expect(poll1.val).toBe(0); - - const poll2 = minNumHeap.poll(true); - expect(poll2).toBeInstanceOf(HeapItem); - poll2 instanceof HeapItem && expect(poll2.val).toBe(1); - - const peek1 = minNumHeap.peek(true); - expect(peek1).toBeInstanceOf(HeapItem); - peek1 instanceof HeapItem && expect(peek1.val).toBe(2); - - const heapArray = minNumHeap.toArray(true); - expect(heapArray).toBeInstanceOf(Array); - expect(heapArray.map(item => item?.priority)).toEqual([2, 5, 9, 6]); - expect(minNumHeap.size).toBe(4); + beforeEach(() => { + minHeap = new MinHeap(numberComparator); }); - it('should object Min Heap operations be proper', function () { - class MyObject { - keyA: string; + test('add and poll elements in ascending order', () => { + minHeap.add(3); + minHeap.add(1); + minHeap.add(4); + minHeap.add(2); - constructor(keyA: string) { - this.keyA = keyA; - } - } + expect(minHeap.poll()).toBe(1); + expect(minHeap.poll()).toBe(2); + expect(minHeap.poll()).toBe(3); + expect(minHeap.poll()).toBe(4); + }); - const minObjHeap = new MinHeap(); + test('peek at the top element without removing it', () => { + minHeap.add(3); + minHeap.add(1); + minHeap.add(4); + minHeap.add(2); - const obj1 = new MyObject('a1'), - obj6 = new MyObject('a6'), - obj2 = new MyObject('a2'), - obj0 = new MyObject('a0'); - minObjHeap.add(1, obj1); - expect(minObjHeap.has(obj1)).toBe(true); - expect(minObjHeap.has(obj6)).toBe(false); - minObjHeap.add(6, obj6); - expect(minObjHeap.has(obj6)).toBe(true); - minObjHeap.add(2, obj2); - expect(minObjHeap.has(obj2)).toBe(true); - minObjHeap.add(0, obj0); - expect(minObjHeap.has(obj0)).toBe(true); + expect(minHeap.peek()).toBe(1); + expect(minHeap.size).toBe(4); + }); - const peek = minObjHeap.peek(true); - peek && peek.val && expect(peek.val.keyA).toBe('a0'); + test('sort elements in ascending order', () => { + minHeap.add(3); + minHeap.add(1); + minHeap.add(4); + minHeap.add(2); - const heapToArr = minObjHeap.toArray(true); - expect(heapToArr.map(item => item?.val?.keyA)).toEqual(['a0', 'a1', 'a2', 'a6']); + const sortedArray = minHeap.sort(); + expect(sortedArray).toEqual([1, 2, 3, 4]); + }); - const values = ['a0', 'a1', 'a2', 'a6']; - let i = 0; - while (minObjHeap.size > 0) { - const polled = minObjHeap.poll(true); - expect(polled).toBeInstanceOf(HeapItem); - polled && expect(polled.val).toBeInstanceOf(MyObject); - polled && polled.val && expect(polled.val.keyA).toBe(values[i]); - i++; - } + test('check if the heap is empty', () => { + expect(minHeap.isEmpty()).toBe(true); + + minHeap.add(5); + expect(minHeap.isEmpty()).toBe(false); + + minHeap.poll(); + expect(minHeap.isEmpty()).toBe(true); }); }); diff --git a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts index 60da9db..ac39ea2 100644 --- a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts @@ -17,11 +17,8 @@ describe('MaxPriorityQueue Operation Test', () => { }); it('should add elements and maintain heap property in a object MaxPriorityQueue', () => { - const priorityQueue = new MaxPriorityQueue<{keyA: number}>({ - nodes: [{keyA: 5}, {keyA: 3}, {keyA: 1}], - comparator: (a, b) => b.keyA - a.keyA - }); - + const priorityQueue = new MaxPriorityQueue<{keyA: number}>((a, b) => b.keyA - a.keyA); + priorityQueue.refill([{keyA: 5}, {keyA: 3}, {keyA: 1}]); priorityQueue.add({keyA: 7}); expect(priorityQueue.poll()?.keyA).toBe(7); @@ -56,7 +53,8 @@ describe('MaxPriorityQueue Operation Test', () => { it('should correctly heapify an array', () => { const array = [5, 3, 7, 1]; - const heap = MaxPriorityQueue.heapify({nodes: array}); + const heap = MaxPriorityQueue.heapify(array, (a, b) => b - a); + heap.refill(array); expect(heap.poll()).toBe(7); expect(heap.poll()).toBe(5); @@ -66,7 +64,7 @@ describe('MaxPriorityQueue Operation Test', () => { it('should correctly heapify an object array', () => { const nodes = [{keyA: 5}, {keyA: 3}, {keyA: 7}, {keyA: 1}]; - const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>({nodes, comparator: (a, b) => b.keyA - a.keyA}); + const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>(nodes, (a, b) => b.keyA - a.keyA); expect(maxPQ.poll()?.keyA).toBe(7); expect(maxPQ.poll()?.keyA).toBe(5); @@ -81,8 +79,8 @@ describe('MaxPriorityQueue Performance Test', () => { new Set(Array.from(new Array(magnitude.LINEAR), () => Math.floor(Math.random() * magnitude.LINEAR * 100))) ); expect(nodes.length).toBeGreaterThan(magnitude.LINEAR / 2); - const maxPQ = new MaxPriorityQueue({nodes}); - + const maxPQ = new MaxPriorityQueue(); + maxPQ.refill(nodes); let prev = Number.MAX_SAFE_INTEGER; const startTime = performance.now(); while (maxPQ.size > 0) { diff --git a/test/unit/data-structures/priority-queue/priority-queue.test.ts b/test/unit/data-structures/priority-queue/priority-queue.test.ts index e25e208..29bcd87 100644 --- a/test/unit/data-structures/priority-queue/priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/priority-queue.test.ts @@ -2,54 +2,37 @@ import {PriorityQueue} from '../../../../src'; import {getRandomInt} from '../../../utils'; describe('PriorityQueue Operation Test', () => { - it('should validate a priority queue', () => { - const minPQ = new PriorityQueue({nodes: [1, 5, 7, 9, 3, 6, 2], comparator: (a, b) => a - b}); - - expect(minPQ.isValid()).toBe(true); - expect(PriorityQueue.isPriorityQueueified({nodes: minPQ.nodes, comparator: (a, b) => a - b})).toBe(true); - expect(PriorityQueue.isPriorityQueueified({nodes: minPQ.nodes, comparator: (a, b) => b - a})).toBe(false); - expect( - PriorityQueue.isPriorityQueueified({ - nodes: [1, 5, 7, 9, 3, 6, 2], - comparator: (a, b) => b - a - }) - ).toBe(false); - }); - it('should PriorityQueue poll, pee, heapify, toArray work well', function () { - const minPQ = new PriorityQueue({nodes: [5, 2, 3, 4, 6, 1], comparator: (a, b) => a - b}); + const minPQ = new PriorityQueue((a, b) => a - b); + minPQ.refill([5, 2, 3, 4, 6, 1]); expect(minPQ.toArray()).toEqual([1, 2, 3, 4, 6, 5]); minPQ.poll(); minPQ.poll(); minPQ.poll(); expect(minPQ.toArray()).toEqual([4, 5, 6]); expect(minPQ.peek()).toBe(4); - expect( - PriorityQueue.heapify({ - nodes: [3, 2, 1, 5, 6, 7, 8, 9, 10], - comparator: (a, b) => a - b - }).toArray() - ).toEqual([1, 2, 3, 5, 6, 7, 8, 9, 10]); + expect(PriorityQueue.heapify([3, 2, 1, 5, 6, 7, 8, 9, 10], (a, b) => a - b).toArray()).toEqual([ + 1, 2, 3, 5, 6, 7, 8, 9, 10 + ]); }); it('should Max PriorityQueue poll, peek, heapify, toArray work well', function () { - const maxPriorityQueue = new PriorityQueue({nodes: [5, 2, 3, 4, 6, 1], comparator: (a, b) => b - a}); + const maxPriorityQueue = new PriorityQueue((a, b) => b - a); + maxPriorityQueue.refill([5, 2, 3, 4, 6, 1]); expect(maxPriorityQueue.toArray()).toEqual([6, 5, 3, 4, 2, 1]); maxPriorityQueue.poll(); maxPriorityQueue.poll(); maxPriorityQueue.poll(); expect(maxPriorityQueue.toArray()).toEqual([3, 2, 1]); expect(maxPriorityQueue.peek()).toBe(3); - expect( - PriorityQueue.heapify({ - nodes: [3, 2, 1, 5, 6, 7, 8, 9, 10], - comparator: (a, b) => a - b - }).toArray() - ).toEqual([1, 2, 3, 5, 6, 7, 8, 9, 10]); + expect(PriorityQueue.heapify([3, 2, 1, 5, 6, 7, 8, 9, 10], (a, b) => a - b).toArray()).toEqual([ + 1, 2, 3, 5, 6, 7, 8, 9, 10 + ]); }); it('should PriorityQueue clone, sort, getNodes, dfs work well', function () { - const minPQ1 = new PriorityQueue({nodes: [2, 5, 8, 3, 1, 6, 7, 4], comparator: (a, b) => a - b}); + const minPQ1 = new PriorityQueue((a, b) => a - b); + minPQ1.refill([2, 5, 8, 3, 1, 6, 7, 4]); const clonedPriorityQueue = minPQ1.clone(); expect(clonedPriorityQueue.getNodes()).toEqual(minPQ1.getNodes()); expect(clonedPriorityQueue.sort()).toEqual([1, 2, 3, 4, 5, 6, 7, 8]); @@ -62,7 +45,8 @@ describe('PriorityQueue Operation Test', () => { describe('Priority Queue Performance Test', () => { it('should numeric heap work well', function () { const values = Array.from(new Array(10000), () => getRandomInt(1, 10000000)); - const minPriorityQueue = new PriorityQueue({nodes: values, comparator: (a, b) => a - b}); + const minPriorityQueue = new PriorityQueue((a, b) => a - b); + minPriorityQueue.refill(values); const sorted = minPriorityQueue.sort(); expect(sorted).toEqual(values.sort((a, b) => a - b)); });