mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
test: reorgnization. docs: improved a lit bit
This commit is contained in:
parent
6b3d8b9fa5
commit
ec649bd8bb
|
@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file.
|
|||
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
|
||||
- [`auto-changelog`](https://github.com/CookPete/auto-changelog)
|
||||
|
||||
## [v1.50.0](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
|
||||
## [v1.50.1](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
|
||||
|
||||
### Changes
|
||||
|
||||
|
|
26
README.md
26
README.md
|
@ -38,58 +38,58 @@ Heap, Binary Tree, Red Black Tree, Linked List, Deque, Trie, Directed Graph, Und
|
|||
<thead>
|
||||
<tr>
|
||||
<th>Method</th>
|
||||
<th>Time Taken (ms)</th>
|
||||
<th>Scale</th>
|
||||
<th>Time Taken</th>
|
||||
<th>Data Scale</th>
|
||||
<th>Belongs To</th>
|
||||
<th>Time Complexity</th>
|
||||
<th>Complexity</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Queue.push & shift</td>
|
||||
<td>5.83</td>
|
||||
<td>5.83 ms</td>
|
||||
<td>100,000</td>
|
||||
<td>data-structure-typed</td>
|
||||
<td>Ours</td>
|
||||
<td>O(1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Array.push & shift</td>
|
||||
<td>2829.59</td>
|
||||
<td>2829.59 ms</td>
|
||||
<td>100,000</td>
|
||||
<td>Native JS</td>
|
||||
<td>O(n)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deque.unshift & shift</td>
|
||||
<td>2.44</td>
|
||||
<td>2.44 ms</td>
|
||||
<td>100,000</td>
|
||||
<td>data-structure-typed</td>
|
||||
<td>Ours</td>
|
||||
<td>O(1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Array.unshift & shift</td>
|
||||
<td>4750.37</td>
|
||||
<td>4750.37 ms</td>
|
||||
<td>100,000</td>
|
||||
<td>Native JS</td>
|
||||
<td>O(n)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>HashMap.set</td>
|
||||
<td>122.51</td>
|
||||
<td>122.51 ms</td>
|
||||
<td>1,000,000</td>
|
||||
<td>data-structure-typed</td>
|
||||
<td>Ours</td>
|
||||
<td>O(1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Map.set</td>
|
||||
<td>223.80</td>
|
||||
<td>223.80 ms</td>
|
||||
<td>1,000,000</td>
|
||||
<td>Native JS</td>
|
||||
<td>O(1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Set.add</td>
|
||||
<td>185.06</td>
|
||||
<td>185.06 ms</td>
|
||||
<td>1,000,000</td>
|
||||
<td>Native JS</td>
|
||||
<td>O(1)</td>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { HashMap, LinkedHashMap } from '../../../../src';
|
||||
import { getRandomInt, getRandomIntArray } from '../../../utils';
|
||||
|
||||
describe('HashMap Test1', () => {
|
||||
describe('HashMap', () => {
|
||||
let hashMap: HashMap<string, number>;
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -84,335 +84,233 @@ describe('HashMap Test1', () => {
|
|||
// Make sure they are stored separately.
|
||||
// expect(hashMap.table[0].length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('HashMap Test2', () => {
|
||||
let hashMap: HashMap;
|
||||
describe('HashMap Test2', () => {
|
||||
let hashMap: HashMap;
|
||||
|
||||
beforeEach(() => {
|
||||
hashMap = new HashMap();
|
||||
});
|
||||
beforeEach(() => {
|
||||
hashMap = new HashMap();
|
||||
});
|
||||
|
||||
it('should create an empty map', () => {
|
||||
expect(hashMap.size).toBe(0);
|
||||
});
|
||||
it('should create an empty map', () => {
|
||||
expect(hashMap.size).toBe(0);
|
||||
});
|
||||
|
||||
it('should add a key-value pair', () => {
|
||||
hashMap.set('key1', 'value1');
|
||||
expect(hashMap.get('key1')).toBe('value1');
|
||||
});
|
||||
it('should add a key-value pair', () => {
|
||||
hashMap.set('key1', 'value1');
|
||||
expect(hashMap.get('key1')).toBe('value1');
|
||||
});
|
||||
|
||||
it('should handle object keys correctly', () => {
|
||||
const keyObj = { id: 1 };
|
||||
hashMap.set(keyObj, 'objectValue');
|
||||
expect(hashMap.get(keyObj)).toBe('objectValue');
|
||||
});
|
||||
it('should handle object keys correctly', () => {
|
||||
const keyObj = { id: 1 };
|
||||
hashMap.set(keyObj, 'objectValue');
|
||||
expect(hashMap.get(keyObj)).toBe('objectValue');
|
||||
});
|
||||
|
||||
test('Inheritability test', () => {
|
||||
class ExtendedHashMap<K, V> extends HashMap<K, V> {
|
||||
someOtherParam?: string;
|
||||
test('Inheritability test', () => {
|
||||
class ExtendedHashMap<K, V> extends HashMap<K, V> {
|
||||
someOtherParam?: string;
|
||||
|
||||
constructor(
|
||||
elements: Iterable<[K, V]> = [],
|
||||
options?: {
|
||||
hashFn?: (key: K) => string;
|
||||
someOtherParam: string;
|
||||
constructor(
|
||||
elements: Iterable<[K, V]> = [],
|
||||
options?: {
|
||||
hashFn?: (key: K) => string;
|
||||
someOtherParam: string;
|
||||
}
|
||||
) {
|
||||
const { someOtherParam, ...restOptions } = options || {};
|
||||
super(elements, restOptions);
|
||||
this.someOtherParam = someOtherParam;
|
||||
}
|
||||
) {
|
||||
const { someOtherParam, ...restOptions } = options || {};
|
||||
super(elements, restOptions);
|
||||
this.someOtherParam = someOtherParam;
|
||||
}
|
||||
}
|
||||
|
||||
const eHM = new ExtendedHashMap<string, number>([], { someOtherParam: 'someOtherParam' });
|
||||
eHM.set('one', 1);
|
||||
expect(eHM.get('one')).toBe(1);
|
||||
});
|
||||
|
||||
test('should raw elements toEntry', () => {
|
||||
const rawCollection = [
|
||||
{ id: 1, name: 'item 1' },
|
||||
{ id: 2, name: 'item 2' }
|
||||
];
|
||||
const hm = new HashMap<number, string, { id: number; name: string }>(rawCollection, {
|
||||
toEntryFn: rawElement => [rawElement.id, rawElement.name]
|
||||
const eHM = new ExtendedHashMap<string, number>([], { someOtherParam: 'someOtherParam' });
|
||||
eHM.set('one', 1);
|
||||
expect(eHM.get('one')).toBe(1);
|
||||
});
|
||||
|
||||
expect(hm.has(1)).toBe(true);
|
||||
expect(hm.get(2)).toBe('item 2');
|
||||
expect(hm.size).toBe(2);
|
||||
});
|
||||
test('should raw elements toEntry', () => {
|
||||
const rawCollection = [
|
||||
{ id: 1, name: 'item 1' },
|
||||
{ id: 2, name: 'item 2' }
|
||||
];
|
||||
const hm = new HashMap<number, string, { id: number; name: string }>(rawCollection, {
|
||||
toEntryFn: rawElement => [rawElement.id, rawElement.name]
|
||||
});
|
||||
|
||||
it('should update the value for an existing key', () => {
|
||||
hashMap.set('key1', 'value1');
|
||||
hashMap.set('key1', 'newValue');
|
||||
expect(hashMap.get('key1')).toBe('newValue');
|
||||
});
|
||||
|
||||
it('should return undefined for a non-existent key', () => {
|
||||
expect(hashMap.get('nonExistentKey')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should remove a key-value pair', () => {
|
||||
hashMap.set('key1', 'value1');
|
||||
hashMap.delete('key1');
|
||||
expect(hashMap.get('key1')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should clear the map', () => {
|
||||
hashMap.set('key1', 'value1');
|
||||
expect(hashMap.size).toBe(1);
|
||||
|
||||
hashMap.clear();
|
||||
expect(hashMap.size).toBe(0);
|
||||
});
|
||||
|
||||
it('should iterate over values', () => {
|
||||
hashMap.set('key1', 'value1');
|
||||
hashMap.set('key2', 'value2');
|
||||
const values = [];
|
||||
for (const value of hashMap) {
|
||||
values.push(value);
|
||||
}
|
||||
expect(values).toEqual([
|
||||
['key1', 'value1'],
|
||||
['key2', 'value2']
|
||||
]);
|
||||
});
|
||||
|
||||
function compareHashMaps(hashMap: HashMap<unknown, unknown>, stdMap: Map<unknown, unknown>) {
|
||||
expect(hashMap.size).toEqual(stdMap.size);
|
||||
stdMap.forEach((value, key) => {
|
||||
expect(hashMap.get(key)).toEqual(value);
|
||||
expect(hm.has(1)).toBe(true);
|
||||
expect(hm.get(2)).toBe('item 2');
|
||||
expect(hm.size).toBe(2);
|
||||
});
|
||||
}
|
||||
|
||||
const stdMap: Map<unknown, unknown> = new Map();
|
||||
const arr: number[] = getRandomIntArray(1000, 1, 10000);
|
||||
it('should update the value for an existing key', () => {
|
||||
hashMap.set('key1', 'value1');
|
||||
hashMap.set('key1', 'newValue');
|
||||
expect(hashMap.get('key1')).toBe('newValue');
|
||||
});
|
||||
|
||||
it('delete test', () => {
|
||||
for (const item of arr) {
|
||||
stdMap.set(item, item);
|
||||
hashMap.set(item, item);
|
||||
}
|
||||
for (const item of arr) {
|
||||
if (Math.random() > 0.6) {
|
||||
expect(hashMap.delete(item)).toEqual(stdMap.delete(item));
|
||||
it('should return undefined for a non-existent key', () => {
|
||||
expect(hashMap.get('nonExistentKey')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should remove a key-value pair', () => {
|
||||
hashMap.set('key1', 'value1');
|
||||
hashMap.delete('key1');
|
||||
expect(hashMap.get('key1')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should clear the map', () => {
|
||||
hashMap.set('key1', 'value1');
|
||||
expect(hashMap.size).toBe(1);
|
||||
|
||||
hashMap.clear();
|
||||
expect(hashMap.size).toBe(0);
|
||||
});
|
||||
|
||||
it('should iterate over values', () => {
|
||||
hashMap.set('key1', 'value1');
|
||||
hashMap.set('key2', 'value2');
|
||||
const values = [];
|
||||
for (const value of hashMap) {
|
||||
values.push(value);
|
||||
}
|
||||
expect(values).toEqual([
|
||||
['key1', 'value1'],
|
||||
['key2', 'value2']
|
||||
]);
|
||||
});
|
||||
|
||||
function compareHashMaps(hashMap: HashMap<unknown, unknown>, stdMap: Map<unknown, unknown>) {
|
||||
expect(hashMap.size).toEqual(stdMap.size);
|
||||
stdMap.forEach((value, key) => {
|
||||
expect(hashMap.get(key)).toEqual(value);
|
||||
});
|
||||
}
|
||||
compareHashMaps(hashMap, stdMap);
|
||||
|
||||
for (let i = 0; i < 1000; ++i) {
|
||||
const random = getRandomInt(0, 100);
|
||||
expect(hashMap.delete(random)).toEqual(stdMap.delete(random));
|
||||
}
|
||||
compareHashMaps(hashMap, stdMap);
|
||||
});
|
||||
});
|
||||
const stdMap: Map<unknown, unknown> = new Map();
|
||||
const arr: number[] = getRandomIntArray(1000, 1, 10000);
|
||||
|
||||
describe('HashMap for coordinate object keys', () => {
|
||||
const hashMap: HashMap<[number, number], number> = new HashMap();
|
||||
const codObjs: [number, number][] = [];
|
||||
|
||||
test('set elements in hash map', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const codObj: [number, number] = [getRandomInt(-10000, 10000), i];
|
||||
codObjs.push(codObj);
|
||||
hashMap.set(codObj, i);
|
||||
}
|
||||
});
|
||||
|
||||
test('get elements in hash map', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const codObj = codObjs[i];
|
||||
if (codObj) {
|
||||
expect(hashMap.get(codObj)).toBe(i);
|
||||
it('delete test', () => {
|
||||
for (const item of arr) {
|
||||
stdMap.set(item, item);
|
||||
hashMap.set(item, item);
|
||||
}
|
||||
}
|
||||
for (const item of arr) {
|
||||
if (Math.random() > 0.6) {
|
||||
expect(hashMap.delete(item)).toEqual(stdMap.delete(item));
|
||||
}
|
||||
}
|
||||
compareHashMaps(hashMap, stdMap);
|
||||
|
||||
for (let i = 0; i < 1000; ++i) {
|
||||
const random = getRandomInt(0, 100);
|
||||
expect(hashMap.delete(random)).toEqual(stdMap.delete(random));
|
||||
}
|
||||
compareHashMaps(hashMap, stdMap);
|
||||
});
|
||||
});
|
||||
|
||||
test('delete elements in hash map', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
if (i === 500) expect(hashMap.size).toBe(500);
|
||||
const codObj = codObjs[i];
|
||||
if (codObj) hashMap.delete(codObj);
|
||||
}
|
||||
expect(hashMap.size).toBe(0);
|
||||
describe('HashMap for coordinate object keys', () => {
|
||||
const hashMap: HashMap<[number, number], number> = new HashMap();
|
||||
const codObjs: [number, number][] = [];
|
||||
|
||||
test('set elements in hash map', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const codObj: [number, number] = [getRandomInt(-10000, 10000), i];
|
||||
codObjs.push(codObj);
|
||||
hashMap.set(codObj, i);
|
||||
}
|
||||
});
|
||||
|
||||
test('get elements in hash map', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const codObj = codObjs[i];
|
||||
if (codObj) {
|
||||
expect(hashMap.get(codObj)).toBe(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('delete elements in hash map', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
if (i === 500) expect(hashMap.size).toBe(500);
|
||||
const codObj = codObjs[i];
|
||||
if (codObj) hashMap.delete(codObj);
|
||||
}
|
||||
expect(hashMap.size).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('HashMap setMany, keys, values', () => {
|
||||
const hm: HashMap<number, number> = new HashMap<number, number>();
|
||||
|
||||
beforeEach(() => {
|
||||
hm.clear();
|
||||
hm.setMany([
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[5, 5]
|
||||
]);
|
||||
hm.setMany([
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[6, 6]
|
||||
]);
|
||||
});
|
||||
|
||||
test('keys', () => {
|
||||
expect([...hm.keys()]).toEqual([2, 3, 4, 5, 6]);
|
||||
});
|
||||
|
||||
test('values', () => {
|
||||
expect([...hm.values()]).toEqual([2, 3, 4, 5, 6]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('HashMap HOF', () => {
|
||||
let hashMap: HashMap;
|
||||
|
||||
beforeEach(() => {
|
||||
hashMap = new HashMap<string, string>();
|
||||
hashMap.set('key1', 'value1');
|
||||
hashMap.set('key2', 'value2');
|
||||
hashMap.set('key3', 'value3');
|
||||
});
|
||||
|
||||
test('every() returns true if all elements match the condition', () => {
|
||||
expect(hashMap.every(value => typeof value === 'string')).toBe(true);
|
||||
});
|
||||
|
||||
test('some() returns true if any element matches the condition', () => {
|
||||
expect(hashMap.some((value, key) => key === 'key1')).toBe(true);
|
||||
});
|
||||
|
||||
test('forEach() should execute a function for each element', () => {
|
||||
const mockCallback = jest.fn();
|
||||
hashMap.forEach(mockCallback);
|
||||
expect(mockCallback.mock.calls.length).toBe(3);
|
||||
});
|
||||
|
||||
test('map() should transform each element', () => {
|
||||
const newHashMap = hashMap.map(value => value.toUpperCase());
|
||||
expect(newHashMap.get('key1')).toBe('VALUE1');
|
||||
});
|
||||
|
||||
test('filter() should remove elements that do not match the condition', () => {
|
||||
const filteredHashMap = hashMap.filter((value, key) => key !== 'key1');
|
||||
expect(filteredHashMap.has('key1')).toBe(false);
|
||||
});
|
||||
|
||||
test('reduce() should accumulate values', () => {
|
||||
const result = hashMap.reduce((acc, value) => acc + value, '');
|
||||
expect(result).toBe('value1value2value3');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('HashMap setMany, keys, values', () => {
|
||||
const hm: HashMap<number, number> = new HashMap<number, number>();
|
||||
|
||||
beforeEach(() => {
|
||||
hm.clear();
|
||||
hm.setMany([
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[5, 5]
|
||||
]);
|
||||
hm.setMany([
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[6, 6]
|
||||
]);
|
||||
});
|
||||
|
||||
test('keys', () => {
|
||||
expect([...hm.keys()]).toEqual([2, 3, 4, 5, 6]);
|
||||
});
|
||||
|
||||
test('values', () => {
|
||||
expect([...hm.values()]).toEqual([2, 3, 4, 5, 6]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('HashMap HOF', () => {
|
||||
let hashMap: HashMap;
|
||||
|
||||
beforeEach(() => {
|
||||
hashMap = new HashMap<string, string>();
|
||||
hashMap.set('key1', 'value1');
|
||||
hashMap.set('key2', 'value2');
|
||||
hashMap.set('key3', 'value3');
|
||||
});
|
||||
|
||||
test('every() returns true if all elements match the condition', () => {
|
||||
expect(hashMap.every(value => typeof value === 'string')).toBe(true);
|
||||
});
|
||||
|
||||
test('some() returns true if any element matches the condition', () => {
|
||||
expect(hashMap.some((value, key) => key === 'key1')).toBe(true);
|
||||
});
|
||||
|
||||
test('forEach() should execute a function for each element', () => {
|
||||
const mockCallback = jest.fn();
|
||||
hashMap.forEach(mockCallback);
|
||||
expect(mockCallback.mock.calls.length).toBe(3);
|
||||
});
|
||||
|
||||
test('map() should transform each element', () => {
|
||||
const newHashMap = hashMap.map(value => value.toUpperCase());
|
||||
expect(newHashMap.get('key1')).toBe('VALUE1');
|
||||
});
|
||||
|
||||
test('filter() should remove elements that do not match the condition', () => {
|
||||
const filteredHashMap = hashMap.filter((value, key) => key !== 'key1');
|
||||
expect(filteredHashMap.has('key1')).toBe(false);
|
||||
});
|
||||
|
||||
test('reduce() should accumulate values', () => {
|
||||
const result = hashMap.reduce((acc, value) => acc + value, '');
|
||||
expect(result).toBe('value1value2value3');
|
||||
});
|
||||
});
|
||||
|
||||
describe('LinkedHashMap Test1', () => {
|
||||
let hashMap: LinkedHashMap<string, number>;
|
||||
|
||||
beforeEach(() => {
|
||||
hashMap = new LinkedHashMap<string, number>();
|
||||
});
|
||||
|
||||
it('should initialize correctly', () => {
|
||||
expect(hashMap.size).toBe(0);
|
||||
// expect(hashMap.table.length).toBe(16);
|
||||
// expect(hashMap.loadFactor).toBe(0.75);
|
||||
// expect(hashMap.capacityMultiplier).toBe(2);
|
||||
// expect(hashMap.initialCapacity).toBe(16);
|
||||
expect(hashMap.isEmpty()).toBe(true);
|
||||
});
|
||||
|
||||
it('should put and get values', () => {
|
||||
hashMap.set('one', 1);
|
||||
hashMap.set('two', 2);
|
||||
hashMap.set('three', 3);
|
||||
|
||||
expect(hashMap.get('one')).toBe(1);
|
||||
expect(hashMap.get('two')).toBe(2);
|
||||
expect(hashMap.get('three')).toBe(3);
|
||||
});
|
||||
|
||||
it('should handle key collisions', () => {
|
||||
// Force a collision by setting two different keys to the same bucket
|
||||
hashMap.set('key1', 1);
|
||||
hashMap.set('key2', 2);
|
||||
|
||||
expect(hashMap.get('key1')).toBe(1);
|
||||
expect(hashMap.get('key2')).toBe(2);
|
||||
});
|
||||
|
||||
it('should delete values', () => {
|
||||
hashMap.set('one', 1);
|
||||
hashMap.set('two', 2);
|
||||
|
||||
hashMap.delete('one');
|
||||
expect(hashMap.get('one')).toBeUndefined();
|
||||
expect(hashMap.size).toBe(1);
|
||||
});
|
||||
|
||||
it('should clear the LinkedHashMap', () => {
|
||||
hashMap.set('one', 1);
|
||||
hashMap.set('two', 2);
|
||||
|
||||
hashMap.clear();
|
||||
expect(hashMap.size).toBe(0);
|
||||
expect(hashMap.isEmpty()).toBe(true);
|
||||
});
|
||||
|
||||
it('should iterate over entries', () => {
|
||||
hashMap.set('one', 1);
|
||||
hashMap.set('two', 2);
|
||||
hashMap.set('three', 3);
|
||||
|
||||
// const entries = Array.from(hashMap.entries());
|
||||
// expect(entries).toContainEqual(['one', 1]);
|
||||
// expect(entries).toContainEqual(['two', 2]);
|
||||
// expect(entries).toContainEqual(['three', 3]);
|
||||
});
|
||||
|
||||
it('should resize the table when load factor is exceeded', () => {
|
||||
// Set a small initial capacity for testing resizing
|
||||
hashMap = new LinkedHashMap<string, number>();
|
||||
|
||||
hashMap.set('one', 1);
|
||||
hashMap.set('two', 2);
|
||||
hashMap.set('three', 3);
|
||||
hashMap.set('four', 4); // This should trigger a resize
|
||||
|
||||
// expect(hashMap.table.length).toBe(8);
|
||||
expect(hashMap.get('one')).toBe(1);
|
||||
expect(hashMap.get('two')).toBe(2);
|
||||
expect(hashMap.get('three')).toBe(3);
|
||||
expect(hashMap.get('four')).toBe(4);
|
||||
});
|
||||
|
||||
it('should allow using a custom hash function', () => {
|
||||
hashMap = new LinkedHashMap<string, number>();
|
||||
|
||||
hashMap.set('one', 1);
|
||||
hashMap.set('two', 2);
|
||||
|
||||
expect(hashMap.get('one')).toBe(1);
|
||||
expect(hashMap.get('two')).toBe(2);
|
||||
// Since the custom hash function always returns 0, these keys will collide.
|
||||
// Make sure they are stored separately.
|
||||
// expect(hashMap.table[0].length).toBe(2);
|
||||
});
|
||||
|
||||
// it('should handle number keys correctly', () => {
|
||||
// const hm = new LinkedHashMap();
|
||||
// hm.set(999, { a: '999Value' });
|
||||
// hm.set('999', {a: '999StrValue'})
|
||||
// expect(hm.get(999)).toEqual({ a: '999Value' });
|
||||
// expect(hm.get('999')).toEqual({ a: '999StrValue1' });
|
||||
// });
|
||||
});
|
||||
|
||||
describe('LinkedHashMap Test2', () => {
|
||||
describe('LinkedHashMap', () => {
|
||||
let hashMap: LinkedHashMap;
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -538,90 +436,192 @@ describe('LinkedHashMap Test2', () => {
|
|||
hashMap.set('key2', 'value2');
|
||||
expect(hashMap.getAt(1)).toBe('value2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('LinkedHashMap for coordinate object keys', () => {
|
||||
const hashMap: LinkedHashMap<[number, number], number> = new LinkedHashMap();
|
||||
const codObjs: [number, number][] = [];
|
||||
describe('LinkedHashMap basic', () => {
|
||||
let hashMap: LinkedHashMap<string, number>;
|
||||
|
||||
test('set elements in hash map', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const codObj: [number, number] = [getRandomInt(-10000, 10000), i];
|
||||
codObjs.push(codObj);
|
||||
hashMap.set(codObj, i);
|
||||
}
|
||||
beforeEach(() => {
|
||||
hashMap = new LinkedHashMap<string, number>();
|
||||
});
|
||||
|
||||
it('should initialize correctly', () => {
|
||||
expect(hashMap.size).toBe(0);
|
||||
// expect(hashMap.table.length).toBe(16);
|
||||
// expect(hashMap.loadFactor).toBe(0.75);
|
||||
// expect(hashMap.capacityMultiplier).toBe(2);
|
||||
// expect(hashMap.initialCapacity).toBe(16);
|
||||
expect(hashMap.isEmpty()).toBe(true);
|
||||
});
|
||||
|
||||
it('should put and get values', () => {
|
||||
hashMap.set('one', 1);
|
||||
hashMap.set('two', 2);
|
||||
hashMap.set('three', 3);
|
||||
|
||||
expect(hashMap.get('one')).toBe(1);
|
||||
expect(hashMap.get('two')).toBe(2);
|
||||
expect(hashMap.get('three')).toBe(3);
|
||||
});
|
||||
|
||||
it('should handle key collisions', () => {
|
||||
// Force a collision by setting two different keys to the same bucket
|
||||
hashMap.set('key1', 1);
|
||||
hashMap.set('key2', 2);
|
||||
|
||||
expect(hashMap.get('key1')).toBe(1);
|
||||
expect(hashMap.get('key2')).toBe(2);
|
||||
});
|
||||
|
||||
it('should delete values', () => {
|
||||
hashMap.set('one', 1);
|
||||
hashMap.set('two', 2);
|
||||
|
||||
hashMap.delete('one');
|
||||
expect(hashMap.get('one')).toBeUndefined();
|
||||
expect(hashMap.size).toBe(1);
|
||||
});
|
||||
|
||||
it('should clear the LinkedHashMap', () => {
|
||||
hashMap.set('one', 1);
|
||||
hashMap.set('two', 2);
|
||||
|
||||
hashMap.clear();
|
||||
expect(hashMap.size).toBe(0);
|
||||
expect(hashMap.isEmpty()).toBe(true);
|
||||
});
|
||||
|
||||
it('should iterate over entries', () => {
|
||||
hashMap.set('one', 1);
|
||||
hashMap.set('two', 2);
|
||||
hashMap.set('three', 3);
|
||||
|
||||
// const entries = Array.from(hashMap.entries());
|
||||
// expect(entries).toContainEqual(['one', 1]);
|
||||
// expect(entries).toContainEqual(['two', 2]);
|
||||
// expect(entries).toContainEqual(['three', 3]);
|
||||
});
|
||||
|
||||
it('should resize the table when load factor is exceeded', () => {
|
||||
// Set a small initial capacity for testing resizing
|
||||
hashMap = new LinkedHashMap<string, number>();
|
||||
|
||||
hashMap.set('one', 1);
|
||||
hashMap.set('two', 2);
|
||||
hashMap.set('three', 3);
|
||||
hashMap.set('four', 4); // This should trigger a resize
|
||||
|
||||
// expect(hashMap.table.length).toBe(8);
|
||||
expect(hashMap.get('one')).toBe(1);
|
||||
expect(hashMap.get('two')).toBe(2);
|
||||
expect(hashMap.get('three')).toBe(3);
|
||||
expect(hashMap.get('four')).toBe(4);
|
||||
});
|
||||
|
||||
it('should allow using a custom hash function', () => {
|
||||
hashMap = new LinkedHashMap<string, number>();
|
||||
|
||||
hashMap.set('one', 1);
|
||||
hashMap.set('two', 2);
|
||||
|
||||
expect(hashMap.get('one')).toBe(1);
|
||||
expect(hashMap.get('two')).toBe(2);
|
||||
// Since the custom hash function always returns 0, these keys will collide.
|
||||
// Make sure they are stored separately.
|
||||
// expect(hashMap.table[0].length).toBe(2);
|
||||
});
|
||||
|
||||
// it('should handle number keys correctly', () => {
|
||||
// const hm = new LinkedHashMap();
|
||||
// hm.set(999, { a: '999Value' });
|
||||
// hm.set('999', {a: '999StrValue'})
|
||||
// expect(hm.get(999)).toEqual({ a: '999Value' });
|
||||
// expect(hm.get('999')).toEqual({ a: '999StrValue1' });
|
||||
// });
|
||||
});
|
||||
|
||||
test('get elements in hash map', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const codObj = codObjs[i];
|
||||
if (codObj) {
|
||||
expect(hashMap.get(codObj)).toBe(i);
|
||||
describe('coordinate object keys', () => {
|
||||
const hashMap: LinkedHashMap<[number, number], number> = new LinkedHashMap();
|
||||
const codObjs: [number, number][] = [];
|
||||
|
||||
test('set elements in hash map', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const codObj: [number, number] = [getRandomInt(-10000, 10000), i];
|
||||
codObjs.push(codObj);
|
||||
hashMap.set(codObj, i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('get elements in hash map', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const codObj = codObjs[i];
|
||||
if (codObj) {
|
||||
expect(hashMap.get(codObj)).toBe(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('delete elements in hash map', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
if (i === 500) expect(hashMap.size).toBe(500);
|
||||
const codObj = codObjs[i];
|
||||
if (codObj) hashMap.delete(codObj);
|
||||
}
|
||||
expect(hashMap.size).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
test('delete elements in hash map', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
if (i === 500) expect(hashMap.size).toBe(500);
|
||||
const codObj = codObjs[i];
|
||||
if (codObj) hashMap.delete(codObj);
|
||||
}
|
||||
expect(hashMap.size).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('LinkedHashMap setMany, keys, values', () => {
|
||||
const hm: LinkedHashMap<number, number> = new LinkedHashMap<number, number>();
|
||||
|
||||
beforeEach(() => {
|
||||
hm.clear();
|
||||
hm.setMany([
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[5, 5]
|
||||
]);
|
||||
hm.setMany([
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[6, 6]
|
||||
]);
|
||||
});
|
||||
|
||||
test('keys', () => {
|
||||
expect([...hm.keys()]).toEqual([2, 3, 4, 5, 6]);
|
||||
});
|
||||
|
||||
test('values', () => {
|
||||
expect([...hm.values()]).toEqual([2, 3, 4, 5, 6]);
|
||||
});
|
||||
|
||||
test('entries', () => {
|
||||
expect([...hm.entries()]).toEqual([
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[5, 5],
|
||||
[6, 6]
|
||||
]);
|
||||
});
|
||||
|
||||
test('every', () => {
|
||||
expect(hm.every(value => value > 4)).toBe(false);
|
||||
});
|
||||
|
||||
test('some', () => {
|
||||
expect(hm.some(value => value > 6)).toBe(false);
|
||||
});
|
||||
|
||||
test('hasValue', () => {
|
||||
expect(hm.hasValue(3)).toBe(true);
|
||||
expect(hm.hasValue(7)).toBe(false);
|
||||
});
|
||||
|
||||
test('print', () => {
|
||||
// hm.print();
|
||||
describe('setMany, keys, values', () => {
|
||||
const hm: LinkedHashMap<number, number> = new LinkedHashMap<number, number>();
|
||||
|
||||
beforeEach(() => {
|
||||
hm.clear();
|
||||
hm.setMany([
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[5, 5]
|
||||
]);
|
||||
hm.setMany([
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[6, 6]
|
||||
]);
|
||||
});
|
||||
|
||||
test('keys', () => {
|
||||
expect([...hm.keys()]).toEqual([2, 3, 4, 5, 6]);
|
||||
});
|
||||
|
||||
test('values', () => {
|
||||
expect([...hm.values()]).toEqual([2, 3, 4, 5, 6]);
|
||||
});
|
||||
|
||||
test('entries', () => {
|
||||
expect([...hm.entries()]).toEqual([
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[5, 5],
|
||||
[6, 6]
|
||||
]);
|
||||
});
|
||||
|
||||
test('every', () => {
|
||||
expect(hm.every(value => value > 4)).toBe(false);
|
||||
});
|
||||
|
||||
test('some', () => {
|
||||
expect(hm.some(value => value > 6)).toBe(false);
|
||||
});
|
||||
|
||||
test('hasValue', () => {
|
||||
expect(hm.hasValue(3)).toBe(true);
|
||||
expect(hm.hasValue(7)).toBe(false);
|
||||
});
|
||||
|
||||
test('print', () => {
|
||||
// hm.print();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue