Skip to content

Commit

Permalink
refactor: Constrain the getter size() from the base class. Refactor s…
Browse files Browse the repository at this point in the history
…ome inappropriate performance tests.

feat: Add sorting capability to performance test reports.
  • Loading branch information
zrwusa committed Jan 9, 2024
1 parent 4747839 commit f8832a0
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 88 deletions.
57 changes: 33 additions & 24 deletions README.md

Large diffs are not rendered by default.

24 changes: 14 additions & 10 deletions src/data-structures/base/iterable-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export abstract class IterableEntryBase<K = any, V = any> {
* Space Complexity: O(1)
*/

abstract get size(): number;

/**
* Time Complexity: O(n)
* Space Complexity: O(1)
Expand Down Expand Up @@ -125,6 +127,11 @@ export abstract class IterableEntryBase<K = any, V = any> {
return false;
}

/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*/

/**
* Time Complexity: O(n)
* Space Complexity: O(1)
Expand Down Expand Up @@ -248,11 +255,6 @@ export abstract class IterableEntryBase<K = any, V = any> {
return;
}

/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*/

/**
* Time Complexity: O(n)
* Space Complexity: O(1)
Expand Down Expand Up @@ -301,6 +303,8 @@ export abstract class IterableEntryBase<K = any, V = any> {
}

export abstract class IterableElementBase<E = any, C = any> {
abstract get size(): number;

/**
* Time Complexity: O(n)
* Space Complexity: O(1)
Expand Down Expand Up @@ -362,6 +366,11 @@ export abstract class IterableElementBase<E = any, C = any> {
return true;
}

/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*/

/**
* Time Complexity: O(n)
* Space Complexity: O(1)
Expand Down Expand Up @@ -445,11 +454,6 @@ export abstract class IterableElementBase<E = any, C = any> {
return;
}

/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*/

/**
* Time Complexity: O(n)
* Space Complexity: O(1)
Expand Down
4 changes: 4 additions & 0 deletions src/data-structures/graph/abstract-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ export abstract class AbstractGraph<
this._vertexMap = v;
}

get size(): number {
return this._vertexMap.size;
}

/**
* In TypeScript, a subclass inherits the interface implementation of its parent class, without needing to implement the same interface again in the subclass. This behavior differs from Java's approach. In Java, if a parent class implements an interface, the subclass needs to explicitly implement the same interface, even if the parent class has already implemented it.
* This means that using abstract methods in the parent class cannot constrain the grandchild classes. Defining methods within an interface also cannot constrain the descendant classes. When inheriting from this class, developers need to be aware that this method needs to be overridden.
Expand Down
2 changes: 1 addition & 1 deletion src/data-structures/heap/heap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export class Heap<E = any> extends IterableElementBase<E> {
* @param element - the element to check.
* @returns Returns true if the specified element is contained; otherwise, returns false.
*/
has(element: E): boolean {
override has(element: E): boolean {
return this.elements.includes(element);
}

Expand Down
6 changes: 3 additions & 3 deletions test/performance/data-structures/binary-tree/avl-tree.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ suite
avl.clear();
for (let i = 0; i < arr.length; i++) avl.add(arr[i]);
})
.add(`${TEN_THOUSAND.toLocaleString()} get`, () => {
for (let i = 0; i < arr.length; i++) avl.get(arr[i]);
})
.add(`${TEN_THOUSAND.toLocaleString()} add & delete randomly`, () => {
avl.clear();
for (let i = 0; i < arr.length; i++) avl.add(arr[i]);
Expand All @@ -20,9 +23,6 @@ suite
.add(`${TEN_THOUSAND.toLocaleString()} addMany`, () => {
avl.clear();
avl.addMany(arr);
})
.add(`${TEN_THOUSAND.toLocaleString()} get`, () => {
for (let i = 0; i < arr.length; i++) avl.get(arr[i]);
});

export { suite };
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ suite
avlTree.clear();
for (let i = 0; i < arr.length; i++) avlTree.add(arr[i]);
})
.add(`${TEN_THOUSAND.toLocaleString()} AVLTree get`, () => {
for (let i = 0; i < arr.length; i++) avlTree.get(arr[i]);
})
.add(`${TEN_THOUSAND.toLocaleString()} AVLTree add & delete randomly`, () => {
avlTree.clear();
for (let i = 0; i < arr.length; i++) avlTree.add(arr[i]);
for (let i = 0; i < arr.length; i++) avlTree.delete(arr[i]);
})
.add(`${TEN_THOUSAND.toLocaleString()} AVLTree get`, () => {
for (let i = 0; i < arr.length; i++) avlTree.get(arr[i]);
});

export { suite };
12 changes: 6 additions & 6 deletions test/performance/data-structures/hash/hash-map.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ if (isCompetitor) {
});
}

suite.add(`Native Map ${MILLION.toLocaleString()} set`, () => {
suite.add(`Native JS Map ${MILLION.toLocaleString()} set`, () => {
const hm = new Map<number, number>();

for (let i = 0; i < MILLION; i++) hm.set(i, i);
});

suite.add(`Native Set ${MILLION.toLocaleString()} add`, () => {
suite.add(`Native JS Set ${MILLION.toLocaleString()} add`, () => {
const hs = new Set<number>();

for (let i = 0; i < MILLION; i++) hs.add(i);
Expand All @@ -49,14 +49,14 @@ if (isCompetitor) {
});
}

suite.add(`Native Map ${MILLION.toLocaleString()} set & get`, () => {
suite.add(`Native JS Map ${MILLION.toLocaleString()} set & get`, () => {
const hm = new Map<number, number>();

for (let i = 0; i < MILLION; i++) hm.set(i, i);
for (let i = 0; i < MILLION; i++) hm.get(i);
});

suite.add(`Native Set ${MILLION.toLocaleString()} add & has`, () => {
suite.add(`Native JS Set ${MILLION.toLocaleString()} add & has`, () => {
const hs = new Set<number>();

for (let i = 0; i < MILLION; i++) hs.add(i);
Expand All @@ -74,7 +74,7 @@ suite.add(`${MILLION.toLocaleString()} ObjKey set & get`, () => {
for (let i = 0; i < MILLION; i++) hm.get(objKeys[i]);
});

suite.add(`Native Map ${MILLION.toLocaleString()} ObjKey set & get`, () => {
suite.add(`Native JS Map ${MILLION.toLocaleString()} ObjKey set & get`, () => {
const hm = new Map<[number, number], number>();
const objs: [number, number][] = [];
for (let i = 0; i < MILLION; i++) {
Expand All @@ -85,7 +85,7 @@ suite.add(`Native Map ${MILLION.toLocaleString()} ObjKey set & get`, () => {
for (let i = 0; i < MILLION; i++) hm.get(objs[i]);
});

suite.add(`Native Set ${MILLION.toLocaleString()} ObjKey add & has`, () => {
suite.add(`Native JS Set ${MILLION.toLocaleString()} ObjKey add & has`, () => {
const hs = new Set<[number, number]>();
const objs: [number, number][] = [];
for (let i = 0; i < MILLION; i++) {
Expand Down
28 changes: 14 additions & 14 deletions test/performance/data-structures/heap/heap.test.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { FibonacciHeap, Heap } from '../../../../src';
import { Heap } from '../../../../src';
import * as Benchmark from 'benchmark';
import { magnitude } from '../../../utils';
import { getRandomInt, magnitude } from '../../../utils';

const suite = new Benchmark.Suite();
const { HUNDRED_THOUSAND, TEN_THOUSAND } = magnitude;
const { HUNDRED_THOUSAND } = magnitude;
const indicesHT = new Array(HUNDRED_THOUSAND).fill(0).map(() => getRandomInt(0, HUNDRED_THOUSAND - 1));

suite
.add(`${HUNDRED_THOUSAND.toLocaleString()} add`, () => {
const heap = new Heap<number>([], { comparator: (a, b) => b - a });
for (let i = 0; i < HUNDRED_THOUSAND; i++) heap.add(indicesHT[i]);
})
.add(`${HUNDRED_THOUSAND.toLocaleString()} add & poll`, () => {
const heap = new Heap<number>([], { comparator: (a, b) => b - a });

for (let i = 0; i < HUNDRED_THOUSAND; i++) heap.add(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) heap.add(indicesHT[i]);
for (let i = 0; i < HUNDRED_THOUSAND; i++) heap.poll();
})
.add(`${HUNDRED_THOUSAND.toLocaleString()} add & dfs`, () => {
const heap = new Heap<number>([], { comparator: (a, b) => b - a });
for (let i = 0; i < HUNDRED_THOUSAND; i++) heap.add(i);
heap.dfs();
})
.add(`${TEN_THOUSAND.toLocaleString()} fib add & pop`, () => {
const fbHeap = new FibonacciHeap<number>();
for (let i = 1; i <= TEN_THOUSAND; i++) fbHeap.push(i);
for (let i = 1; i <= TEN_THOUSAND; i++) fbHeap.pop();
});
// .add(`${TEN_THOUSAND.toLocaleString()} fib add & pop`, () => {
// const fbHeap = new FibonacciHeap<number>();
// for (let i = 1; i <= TEN_THOUSAND; i++) fbHeap.push(i);
// for (let i = 1; i <= TEN_THOUSAND; i++) fbHeap.pop();
// });

export { suite };
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import { PriorityQueue as CPriorityQueue } from 'js-sdsl';
import { PriorityQueue } from '../../../../src';
import { PriorityQueue as CPriorityQueue } from 'js-sdsl';
import * as Benchmark from 'benchmark';
import { magnitude } from '../../../utils';
import { isCompetitor } from '../../../config';

const suite = new Benchmark.Suite();
const { HUNDRED_THOUSAND } = magnitude;

suite.add(`${HUNDRED_THOUSAND.toLocaleString()} add & poll`, () => {
const pq = new PriorityQueue<number>([], { comparator: (a, b) => b - a });
suite
.add(`${HUNDRED_THOUSAND.toLocaleString()} add`, () => {
const heap = new PriorityQueue<number>([], { comparator: (a, b) => b - a });
for (let i = 0; i < HUNDRED_THOUSAND; i++) heap.add(i);
})
.add(`${HUNDRED_THOUSAND.toLocaleString()} add & poll`, () => {
const heap = new PriorityQueue<number>([], { comparator: (a, b) => b - a });

for (let i = 0; i < HUNDRED_THOUSAND; i++) pq.add(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) pq.poll();
});
for (let i = 0; i < HUNDRED_THOUSAND; i++) heap.add(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) heap.poll();
});
if (isCompetitor) {
suite.add(`CPT ${HUNDRED_THOUSAND.toLocaleString()} add & pop`, () => {
const pq = new CPriorityQueue<number>();
Expand Down
16 changes: 8 additions & 8 deletions test/performance/data-structures/queue/deque.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,25 @@ if (isCompetitor) {
}

suite
// .add(`${TEN_THOUSAND.toLocaleString()} push & delete`, () => {
// const deque = new Deque<number>();
//
// for (let i = 0; i < TEN_THOUSAND; i++) deque.push(i);
// for (let i = 0; i < TEN_THOUSAND; i++) deque.delete(randomIndicesTenThousand[i]);
// })
.add(`${MILLION.toLocaleString()} push & pop`, () => {
const deque = new Deque<number>();

for (let i = 0; i < MILLION; i++) deque.push(i);
for (let i = 0; i < MILLION; i++) deque.pop();
})
.add(`${MILLION.toLocaleString()} push & shift`, () => {
const deque = new Deque<number>();

for (let i = 0; i < MILLION; i++) deque.push(i);
for (let i = 0; i < MILLION; i++) deque.shift();
})
.add(`${HUNDRED_THOUSAND.toLocaleString()} push & shift`, () => {
const deque = new Deque<number>();

for (let i = 0; i < HUNDRED_THOUSAND; i++) deque.push(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) deque.shift();
})
.add(`Native Array ${HUNDRED_THOUSAND.toLocaleString()} push & shift`, () => {
.add(`Native JS Array ${HUNDRED_THOUSAND.toLocaleString()} push & shift`, () => {
const array = new Array<number>();

for (let i = 0; i < HUNDRED_THOUSAND; i++) array.push(i);
Expand All @@ -51,7 +51,7 @@ suite
for (let i = 0; i < HUNDRED_THOUSAND; i++) deque.unshift(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) deque.shift();
})
.add(`Native Array ${HUNDRED_THOUSAND.toLocaleString()} unshift & shift`, () => {
.add(`Native JS Array ${HUNDRED_THOUSAND.toLocaleString()} unshift & shift`, () => {
const array = new Array<number>();

for (let i = 0; i < HUNDRED_THOUSAND; i++) array.unshift(i);
Expand Down
17 changes: 5 additions & 12 deletions test/performance/data-structures/queue/queue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,11 @@ suite.add(`${HUNDRED_THOUSAND.toLocaleString()} push & shift`, () => {
for (let i = 0; i < HUNDRED_THOUSAND; i++) queue.push(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) queue.shift();
});
suite
.add(`Native Array ${HUNDRED_THOUSAND.toLocaleString()} push & shift`, () => {
const arr = new Array<number>();
suite.add(`Native JS Array ${HUNDRED_THOUSAND.toLocaleString()} push & shift`, () => {
const arr = new Array<number>();

for (let i = 0; i < HUNDRED_THOUSAND; i++) arr.push(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) arr.shift();
})
.add(`Native Array ${HUNDRED_THOUSAND.toLocaleString()} push & pop`, () => {
const arr = new Array<number>();

for (let i = 0; i < HUNDRED_THOUSAND; i++) arr.push(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) arr.pop();
});
for (let i = 0; i < HUNDRED_THOUSAND; i++) arr.push(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) arr.shift();
});

export { suite };
44 changes: 43 additions & 1 deletion test/performance/reportor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as fs from 'fs';
import * as fastGlob from 'fast-glob';
import { Color, numberFix, render } from '../utils';
import { PerformanceTest } from './types';
import * as console from 'console';

const args = process.argv.slice(2);

Expand Down Expand Up @@ -171,7 +172,48 @@ function replaceMarkdownContent(startMarker: string, endMarker: string, newText:
});
}

performanceTests.forEach(item => {
const order = [
'heap',
'rb-tree',
'queue',
'deque',
'hash-map',
'trie',
'avl-tree',
'binary-tree-overall',
'directed-graph',
'doubly-linked-list',
'singly-linked-list',
'priority-queue',
'stack'
];

const sortedPerformanceTests = [...performanceTests].sort((a, b) => {
const indexA = order.indexOf(a.testName);
const indexB = order.indexOf(b.testName);

// If both a and b are in the order, sort them according to their indices in the order.
if (indexA !== -1 && indexB !== -1) {
return indexA - indexB;
}

// If there is only 'a' in the order, then place 'b' in front.
if (indexA !== -1) {
return 1;
}

// If only b is in the order, then a should be placed before it.
if (indexB !== -1) {
return -1;
}

// If neither a nor b are in order, keep their original order
return 0;
});

console.log(`${GREEN} Found tests${END}: ${sortedPerformanceTests.map(test => test.testName)}`);

sortedPerformanceTests.forEach(item => {
const { suite, testName, file } = item;

console.log(coloredLabeled('Running', file));
Expand Down

0 comments on commit f8832a0

Please sign in to comment.