UNPKG

data-structure-typed

Version:
671 lines (560 loc) 18.7 kB
import { LinkedListQueue, Queue } from '../../../../src'; // import { isDebugTest } from '../../../config'; // const isDebug = isDebugTest; describe('Queue', () => { let queue: Queue<number>; beforeEach(() => { queue = new Queue<number>(); }); it('new Queue() should create an empty queue', () => { expect(queue.length).toBe(0); expect(queue.isEmpty()).toBeTruthy(); }); it('push should add elements to the queue', () => { queue.push(1); queue.push(2); expect(queue.length).toBe(2); }); it('shift should remove the first element', () => { queue.push(1); queue.push(2); expect(queue.shift()).toBe(1); expect(queue.length).toBe(1); }); it('shift should return undefined if queue is empty', () => { expect(queue.shift()).toBeUndefined(); }); it('first should return the first element without removing it', () => { queue.push(1); queue.push(2); expect(queue.first).toBe(1); expect(queue.length).toBe(2); }); it('first should return undefined if queue is empty', () => { expect(queue.first).toBeUndefined(); }); it('length should return the number of elements', () => { queue.push(1); queue.push(2); expect(queue.length).toBe(2); }); it('isEmpty should return true if the queue is empty', () => { expect(queue.isEmpty()).toBeTruthy(); }); it('isEmpty should return false if the queue is not empty', () => { queue.push(1); expect(queue.isEmpty()).toBeFalsy(); }); it('toArray should return an array of queue elements', () => { queue.push(1); queue.push(2); expect(queue.toArray()).toEqual([1, 2]); }); it('clear should remove all elements from the queue', () => { queue.push(1); queue.push(2); queue.clear(); expect(queue.length).toBe(0); }); it('forEach should iterate over all elements', () => { const arr: number[] = []; queue.push(1); queue.push(2); queue.forEach(element => arr.push(element)); expect(arr).toEqual([1, 2]); }); // Boundary value testing it('push and shift with many elements', () => { for (let i = 0; i < 1000; i++) { queue.push(i); } for (let i = 0; i < 1000; i++) { expect(queue.shift()).toBe(i); } expect(queue.isEmpty()).toBeTruthy(); }); it('push with maxLen', () => { const queue = new Queue<number>([], { maxLen: 10 }); for (let i = 0; i < 1000; i++) { queue.push(i); } expect(queue.maxLen).toBe(10); expect(queue.length).toBe(10); expect(queue.first).toBe(990); }); it('compact method should work well', () => { for (let i = 0; i < 1000; i++) queue.push(i); for (let i = 0; i < 499; i++) queue.shift(); expect(queue.elements.length).toBe(1000); queue.compact(); expect(queue.elements.length).toBe(501); }); it('should at after shifting', () => { for (let i = 0; i < 100; i++) { queue.push(i); } for (let i = 0; i < 10; i++) { expect(queue.shift()).toBe(i); } for (let i = 0; i < 90; i++) { expect(queue.at(i)).toBe(i + 10); } }); it('should toElementFn', () => { const queue = new Queue<string, { id: string }>([{ id: '1' }, { id: '5' }, { id: '3' }, { id: '4' }, { id: '2' }], { toElementFn: rawElement => rawElement.id }); expect(queue.length).toBe(5); queue.shift(); expect(queue.length).toBe(4); expect(queue.at(1)).toBe('3'); }); it('should object queue map & filter', function () { const queue = new Queue<{ a: string; key: number; }>([ { key: 1, a: 'a1' }, { key: 6, a: 'a6' }, { key: 5, a: 'a5' }, { key: 3, a: 'a3' }, { key: 2, a: 'a2' }, { key: 4, a: 'a4' }, { key: 0, a: 'a0' } ]); const mappedQueue = queue.map(item => item.key); expect(mappedQueue.at(0)).toBe(1); expect([...mappedQueue]).toEqual([1, 6, 5, 3, 2, 4, 0]); const mappedToElementFnQueue = queue.map<string, { id: string }>( item => item.key.toString(), rawElement => rawElement.id ); expect(mappedToElementFnQueue.at(0)).toBe('1'); expect([...mappedToElementFnQueue]).toEqual(['1', '6', '5', '3', '2', '4', '0']); const filteredQueue = queue.filter(item => item.key > 3); expect(filteredQueue.at(0)).toEqual({ a: 'a6', key: 6 }); expect([...filteredQueue]).toEqual([ { a: 'a6', key: 6 }, { a: 'a5', key: 5 }, { a: 'a4', key: 4 } ]); }); it('should clone', function () { const queue = new Queue<string>(); queue.push('1'); queue.push('6'); queue.push('2'); queue.push('0'); queue.push('5'); queue.push('9'); queue.delete('2'); expect([...queue]).toEqual(['1', '6', '0', '5', '9']); const cloned = queue.clone(); expect([...cloned]).toEqual(['1', '6', '0', '5', '9']); queue.delete('5'); expect([...queue]).toEqual(['1', '6', '0', '9']); queue.deleteAt(2); expect([...queue]).toEqual(['1', '6', '9']); expect([...cloned]).toEqual(['1', '6', '0', '5', '9']); }); it('should set autoCompactRatio', function () { const queue = new Queue<number>(); queue.autoCompactRatio = 0.3; queue.push(1); queue.push(2); queue.push(3); queue.push(4); queue.push(5); queue.push(6); queue.push(7); queue.push(8); queue.push(9); queue.push(10); expect(queue.elements.length).toBe(10); while (queue.length > 7) queue.shift(); expect(queue.length).toBe(7); expect(queue.elements.length).toBe(10); queue.shift(); expect(queue.length).toBe(6); expect(queue.elements.length).toBe(6); }); }); describe('Queue - Advanced Methods', () => { let queue: Queue<number>; beforeEach(() => { queue = new Queue<number>(); }); it('reduce should apply a function against an accumulator and each element', () => { queue.push(1); queue.push(2); queue.push(3); const sum = queue.reduce((acc, val) => acc + val, 0); expect(sum).toBe(6); }); it('reduce should return initial value for empty queue', () => { const initialValue = 0; const sum = queue.reduce((acc, val) => acc + val, initialValue); expect(sum).toBe(initialValue); }); it('filter should return a new queue with all elements that pass the test implemented by provided function', () => { queue.push(1); queue.push(2); queue.push(3); const filteredQueue = queue.filter(val => val > 1); expect(filteredQueue.toArray()).toEqual([2, 3]); }); it('filter should return an empty queue for empty queue', () => { const filteredQueue = queue.filter(val => val > 1); expect(filteredQueue.isEmpty()).toBeTruthy(); }); it('map should create a new queue with the results of calling a provided function on every element', () => { queue.push(1); queue.push(2); queue.push(3); const mappedQueue = queue.map(val => val * 2); expect(mappedQueue.toArray()).toEqual([2, 4, 6]); }); it('map should return an empty queue for empty queue', () => { const mappedQueue = queue.map(val => val * 2); expect(mappedQueue.isEmpty()).toBeTruthy(); }); }); describe('Queue - Additional Methods', () => { let queue: Queue<number>; beforeEach(() => { queue = new Queue<number>(); }); it('peekLast should return the last element without removing it', () => { queue.push(1); queue.push(2); expect(queue.last).toBe(2); expect(queue.length).toBe(2); }); it('peekLast should return undefined if queue is empty', () => { expect(queue.last).toBeUndefined(); }); it('at should return the element at the specified index', () => { queue.push(1); queue.push(2); queue.push(3); expect(queue.at(1)).toBe(2); }); it('at should return undefined for an invalid index', () => { queue.push(1); expect(queue.at(3)).toBeUndefined(); expect(queue.at(-1)).toBeUndefined(); }); it('print should not throw any errors', () => { expect(() => { queue.push(1); // queue.print(); }).not.toThrow(); }); }); describe('Queue Additional Methods', () => { // Slice method implementation and test test('slice should return a new list with specified range', () => { const list = new Queue([1, 2, 3, 4, 5]); const slicedList = list.slice(1, 4); expect(slicedList.toArray()).toEqual([2, 3, 4]); expect(list.length).toBe(5); // Original list unchanged }); // Splice method implementation test('splice should modify list and return removed elements', () => { const list = new Queue([1, 2, 3, 4, 5]); const removedList = list.splice(2, 2, 6, 7); expect(list.toArray()).toEqual([1, 2, 6, 7, 5]); expect(removedList.toArray()).toEqual([3, 4]); }); // Concat method test test('concat should combine multiple lists', () => { const list1 = new Queue([1, 2]); const list2 = new Queue([3, 4]); const list3 = new Queue([5, 6]); const concatenatedList = list1.concat(list2, list3); expect(concatenatedList.toArray()).toEqual([1, 2, 3, 4, 5, 6]); }); // Sort method test test('sort should order elements in ascending order', () => { const list = new Queue([5, 2, 8, 1, 9]); list.sort((a, b) => a - b); expect(list.toArray()).toEqual([1, 2, 5, 8, 9]); }); // Reverse method test test('reverse should invert the list order', () => { const list = new Queue([1, 2, 3, 4, 5]); list.reverse(); expect(list.toArray()).toEqual([5, 4, 3, 2, 1]); }); // Join method test test('join should convert list to string with separator', () => { const list = new Queue(['a', 'b', 'c']); expect(list.join('-')).toBe('a-b-c'); expect(list.join()).toBe('a,b,c'); }); // IndexOf method test test('indexOf should return first occurrence index', () => { const list = new Queue([1, 2, 3, 2, 1]); expect(list.indexOf(2)).toBe(1); expect(list.indexOf(4)).toBe(-1); }); // LastIndexOf method test test('lastIndexOf should return last occurrence index', () => { const list = new Queue([1, 2, 3, 2, 1]); expect(list.lastIndexOf(2)).toBe(3); expect(list.lastIndexOf(4)).toBe(-1); }); // findIndex method test test('findIndex should return first occurrence index', () => { const list = new Queue([1, 2, 3, 2, 1]); expect(list.findIndex(item => item === 2)).toBe(1); expect(list.findIndex(item => item === 4)).toBe(-1); }); // fill method test test('fill should return fill all the list', () => { let list = new Queue([1, 2, 3, 2, 1]); expect([...list.fill(9)]).toEqual([9, 9, 9, 9, 9]); list = new Queue([1, 2, 3, 2, 1]); expect([...list.fill(9, 2, 3)]).toEqual([1, 2, 9, 2, 1]); list = new Queue([1, 2, 3, 2, 1]); expect([...list.fill(9, -3, -2)]).toEqual([1, 2, 9, 2, 1]); list = new Queue([1, 2, 3, 2, 1]); expect([...list.fill(9, -2, -3)]).toEqual([1, 2, 3, 2, 1]); }); }); describe('Queue - Static and Clone Methods', () => { it('fromArray should create a new queue from an array', () => { const array = [1, 2, 3]; const queue = Queue.fromArray(array); expect(queue.toArray()).toEqual(array); expect(queue.length).toBe(array.length); }); it('fromArray should create an empty queue from an empty array', () => { const queue = Queue.fromArray([]); expect(queue.isEmpty()).toBeTruthy(); }); it('clone should create a new queue with the same elements', () => { const originalQueue = new Queue<number>(); originalQueue.push(1); originalQueue.push(2); const clonedQueue = originalQueue.clone(); expect(clonedQueue.toArray()).toEqual(originalQueue.toArray()); expect(clonedQueue.length).toBe(originalQueue.length); }); it('clone should not affect the original queue when mutated', () => { const originalQueue = new Queue<number>(); originalQueue.push(1); originalQueue.push(2); const clonedQueue = originalQueue.clone(); clonedQueue.push(3); expect(clonedQueue.length).not.toBe(originalQueue.length); expect(originalQueue.toArray()).not.toContain(3); }); }); describe('LinkedListQueue', () => { let queue: LinkedListQueue<string>; beforeEach(() => { queue = new LinkedListQueue<string>(); queue.push('A'); queue.push('B'); }); it('should push elements to the end of the queue', () => { expect(queue.first).toBe('A'); expect(queue.length).toBe(2); }); it('should shift elements from the front of the queue', () => { const dequeued = queue.shift(); expect(dequeued).toBe('A'); expect(queue.first).toBe('B'); expect(queue.length).toBe(1); }); it('should peek at the front of the queue', () => { expect(queue.first).toBe('A'); }); it('should clone method work correctly', () => { const cloned = queue.clone(); expect(cloned instanceof LinkedListQueue).toBe(true); expect(cloned.length).toBe(2); }); }); describe('Queue', () => { // Test queue initialization it('should initialize correctly with no elements', () => { const queue = new Queue(); expect(queue.isEmpty()).toBe(true); expect(queue.length).toBe(0); expect(queue.first).toBeUndefined(); expect(queue.last).toBeUndefined(); }); it('should initialize correctly with given elements', () => { const queue = new Queue([1, 2, 3]); expect(queue.length).toBe(3); expect(queue.first).toBe(1); expect(queue.last).toBe(3); }); // Test push and pushMany it('should add elements to the queue', () => { const queue = new Queue<number>(); queue.push(1); queue.push(2); expect(queue.length).toBe(2); expect(queue.first).toBe(1); expect(queue.last).toBe(2); }); it('should add multiple elements using pushMany', () => { const queue = new Queue<number>(); queue.pushMany([1, 2, 3]); expect(queue.length).toBe(3); expect(queue.elements).toEqual([1, 2, 3]); }); // Test shift it('should remove the first element from the queue', () => { const queue = new Queue([1, 2, 3]); const shifted = queue.shift(); expect(shifted).toBe(1); expect(queue.length).toBe(2); expect(queue.first).toBe(2); }); // Test delete and deleteAt it('should delete an element from the queue', () => { const queue = new Queue([1, 2, 3]); const result = queue.delete(2); expect(result).toBe(true); expect(queue.elements).toEqual([1, 3]); }); it('should delete an element at a specific index', () => { const queue = new Queue([1, 2, 3]); const deleted = queue.deleteAt(1); expect(deleted).toBe(2); expect(queue.elements).toEqual([1, 3]); }); // Test at it('should retrieve an element by index', () => { const queue = new Queue([1, 2, 3]); expect(queue.at(0)).toBe(1); expect(queue.at(2)).toBe(3); }); // Test reverse it('should reverse the queue', () => { const queue = new Queue([1, 2, 3]); queue.reverse(); expect(queue.elements).toEqual([3, 2, 1]); expect(queue.first).toBe(3); expect(queue.last).toBe(1); }); // Test addAt it('should add an element at a specific index', () => { const queue = new Queue([1, 3]); const result = queue.addAt(1, 2); expect(result).toBe(true); expect(queue.elements).toEqual([1, 2, 3]); }); // Test setAt it('should set an element at a specific index', () => { const queue = new Queue([1, 2, 3]); const result = queue.setAt(1, 10); expect(result).toBe(true); expect(queue.elements).toEqual([1, 10, 3]); }); // Test clear it('should clear the queue', () => { const queue = new Queue([1, 2, 3]); queue.clear(); expect(queue.isEmpty()).toBe(true); expect(queue.length).toBe(0); }); // Test compact it('should compact the queue', () => { const queue = new Queue([1, 2, 3]); queue.shift(); queue.shift(); queue.compact(); expect(queue.elements).toEqual([3]); }); // Test splice it('should splice elements from the queue', () => { const queue = new Queue([1, 2, 3, 4]); const removed = queue.splice(1, 2); expect(removed.elements).toEqual([2, 3]); expect(queue.elements).toEqual([1, 4]); }); // Test clone it('should create a clone of the queue', () => { const queue = new Queue([1, 2, 3]); const clone = queue.clone(); expect(clone.elements).toEqual(queue.elements); clone.push(4); expect(queue.elements).not.toContain(4); }); // Test filter it('should filter elements based on a predicate', () => { const queue = new Queue([1, 2, 3, 4]); const filtered = queue.filter(el => el % 2 === 0); expect(filtered.elements).toEqual([2, 4]); }); // Test map it('should map elements to a new queue', () => { const queue = new Queue([1, 2, 3]); const mapped = queue.map(el => el * 2); expect(mapped.elements).toEqual([2, 4, 6]); }); }); describe('classic uses', () => { it('@example Sliding Window using Queue', () => { const nums = [2, 3, 4, 1, 5]; const k = 2; const queue = new Queue<number>(); let maxSum = 0; let currentSum = 0; nums.forEach((num) => { queue.push(num); currentSum += num; if (queue.length > k) { currentSum -= queue.shift()!; } if (queue.length === k) { maxSum = Math.max(maxSum, currentSum); } }); expect(maxSum).toBe(7); // Maximum sum is from subarray [3, 4]. }); it('@example Breadth-First Search (BFS) using Queue', () => { const graph: { [key in number]: number[] } = { 1: [2, 3], 2: [4, 5], 3: [], 4: [], 5: [] }; const queue = new Queue<number>(); const visited: number[] = []; queue.push(1); while (!queue.isEmpty()) { const node = queue.shift()!; if (!visited.includes(node)) { visited.push(node); graph[node].forEach(neighbor => queue.push(neighbor)); } } expect(visited).toEqual([1, 2, 3, 4, 5]); // Expected BFS traversal order. }); it('Task Scheduling using Queue', () => { const tasks = ['A', 'A', 'A', 'B', 'B', 'B']; const cooldown = 2; const taskQueue = new Queue<string>(); const cooldownQueue = new Queue<string>(); for (const task of tasks) { while (!cooldownQueue.isEmpty() && cooldownQueue.first === task) { cooldownQueue.shift(); taskQueue.push('idle'); } taskQueue.push(task); cooldownQueue.push(task); if (cooldownQueue.length > cooldown) { cooldownQueue.shift(); } } const scheduled = taskQueue.elements; expect(scheduled).toEqual(['A', 'idle', 'A', 'idle', 'A', 'B', 'B', 'idle', 'idle', 'B']); }); });