Merge pull request #6 from zrwusa/enhance1.36.1

[BinaryTree, Heap] In abstract classes, only retain abstract methods.…
This commit is contained in:
zrwusa 2023-10-16 20:37:34 +08:00 committed by GitHub
commit 1740b3503f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 1587 additions and 1607 deletions

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "data-structure-typed",
"version": "1.40.0-rc",
"version": "1.36.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "data-structure-typed",
"version": "1.40.0-rc",
"version": "1.36.0",
"license": "MIT",
"devDependencies": {
"@types/benchmark": "^2.1.3",

File diff suppressed because it is too large Load diff

View file

@ -9,9 +9,9 @@ import {BST, BSTNode} from './bst';
import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeKey} from '../../types';
import {IAVLTree, IAVLTreeNode} from '../../interfaces';
export class AVLTreeNode<V = any, NEIGHBOR extends AVLTreeNode<V, NEIGHBOR> = AVLTreeNodeNested<V>>
extends BSTNode<V, NEIGHBOR>
implements IAVLTreeNode<V, NEIGHBOR>
export class AVLTreeNode<V = any, FAMILY extends AVLTreeNode<V, FAMILY> = AVLTreeNodeNested<V>>
extends BSTNode<V, FAMILY>
implements IAVLTreeNode<V, FAMILY>
{
height: number;

File diff suppressed because it is too large Load diff

View file

@ -16,9 +16,9 @@ import {CP, LoopType} from '../../types';
import {BinaryTree, BinaryTreeNode} from './binary-tree';
import {IBST, IBSTNode} from '../../interfaces';
export class BSTNode<V = any, NEIGHBOR extends BSTNode<V, NEIGHBOR> = BSTNodeNested<V>>
extends BinaryTreeNode<V, NEIGHBOR>
implements IBSTNode<V, NEIGHBOR>
export class BSTNode<V = any, FAMILY extends BSTNode<V, FAMILY> = BSTNodeNested<V>>
extends BinaryTreeNode<V, FAMILY>
implements IBSTNode<V, FAMILY>
{
constructor(key: BinaryTreeNodeKey, val?: V) {
super(key, val);

View file

@ -2,9 +2,9 @@ import {BinaryTreeNodeKey, RBColor, RBTreeNodeNested, RBTreeOptions} from '../..
import {IRBTree, IRBTreeNode} from '../../interfaces';
import {BST, BSTNode} from './bst';
export class RBTreeNode<V = any, NEIGHBOR extends RBTreeNode<V, NEIGHBOR> = RBTreeNodeNested<V>>
extends BSTNode<V, NEIGHBOR>
implements IRBTreeNode<V, NEIGHBOR>
export class RBTreeNode<V = any, FAMILY extends RBTreeNode<V, FAMILY> = RBTreeNodeNested<V>>
extends BSTNode<V, FAMILY>
implements IRBTreeNode<V, FAMILY>
{
private _color: RBColor;

View file

@ -10,9 +10,9 @@ import {BinaryTreeDeletedResult, CP, DFSOrderPattern, FamilyPosition, LoopType}
import {ITreeMultiset, ITreeMultisetNode} from '../../interfaces';
import {AVLTree, AVLTreeNode} from './avl-tree';
export class TreeMultisetNode<V = any, NEIGHBOR extends TreeMultisetNode<V, NEIGHBOR> = TreeMultisetNodeNested<V>>
extends AVLTreeNode<V, NEIGHBOR>
implements ITreeMultisetNode<V, NEIGHBOR>
export class TreeMultisetNode<V = any, FAMILY extends TreeMultisetNode<V, FAMILY> = TreeMultisetNodeNested<V>>
extends AVLTreeNode<V, FAMILY>
implements ITreeMultisetNode<V, FAMILY>
{
/**
* The constructor function initializes a BinaryTreeNode object with a key, value, and count.

View file

@ -7,11 +7,11 @@
import type {CompareFunction} from '../../types';
export class Heap<T> {
private nodes: T[] = [];
private readonly comparator: CompareFunction<T>;
export class Heap<E> {
protected nodes: E[] = [];
private readonly comparator: CompareFunction<E>;
constructor(comparator: CompareFunction<T>) {
constructor(comparator: CompareFunction<E>) {
this.comparator = comparator;
}
@ -19,7 +19,7 @@ export class Heap<T> {
* Insert an element into the heap and maintain the heap properties.
* @param value - The element to be inserted.
*/
add(value: T): Heap<T> {
add(value: E): Heap<E> {
this.nodes.push(value);
this.bubbleUp(this.nodes.length - 1);
return this;
@ -29,16 +29,16 @@ export class Heap<T> {
* Remove and return the top element (smallest or largest element) from the heap.
* @returns The top element or null if the heap is empty.
*/
poll(): T | null {
poll(): E | null {
if (this.nodes.length === 0) {
return null;
}
if (this.nodes.length === 1) {
return this.nodes.pop() as T;
return this.nodes.pop() as E;
}
const topValue = this.nodes[0];
this.nodes[0] = this.nodes.pop() as T;
this.nodes[0] = this.nodes.pop() as E;
this.sinkDown(0);
return topValue;
}
@ -98,7 +98,7 @@ export class Heap<T> {
* Peek at the top element of the heap without removing it.
* @returns The top element or null if the heap is empty.
*/
peek(): T | null {
peek(): E | null {
if (this.nodes.length === 0) {
return null;
}
@ -116,7 +116,7 @@ export class Heap<T> {
* Get the last element in the heap, which is not necessarily a leaf node.
* @returns The last element or null if the heap is empty.
*/
leaf(): T | null {
get leaf(): E | null {
return this.nodes[this.size - 1] ?? null;
}
@ -128,11 +128,18 @@ export class Heap<T> {
return this.size === 0;
}
/**
* Reset the nodes of the heap. Make the nodes empty.
*/
clear() {
this.nodes = [];
}
refill(nodes: T[]) {
/**
* Clear and add nodes of the heap
* @param nodes
*/
refill(nodes: E[]) {
this.nodes = nodes;
this.fix();
}
@ -142,41 +149,17 @@ export class Heap<T> {
* @param value - the element to check.
* @returns Returns true if the specified element is contained; otherwise, returns false.
*/
has(value: T): boolean {
has(value: E): boolean {
return this.nodes.includes(value);
}
/**
* Use a comparison function to find the index of an element in the heap.
* @param value - the element to find.
* @param index - the index currently being searched.
* @returns The index of the element, or -1 if not found.
*/
private findIndex(value: T, index: number): number {
if (index >= this.size) {
return -1;
}
const compareResult = this.comparator(value, this.nodes[index]);
if (compareResult === 0) {
return index; // Element found
} else if (compareResult < 0) {
// The element should be in the left subtree
return this.findIndex(value, 2 * index + 1);
} else {
// The element should be in the right subtree
return this.findIndex(value, 2 * index + 2);
}
}
/**
* Depth-first search (DFS) method, different traversal orders can be selected
* @param order - Traversal order parameter: 'in' (in-order), 'pre' (pre-order) or 'post' (post-order).
* @returns An array containing elements traversed in the specified order.
*/
dfs(order: 'in' | 'pre' | 'post'): T[] {
const result: T[] = [];
dfs(order: 'in' | 'pre' | 'post'): E[] {
const result: E[] = [];
// Auxiliary recursive function, traverses the binary heap according to the traversal order
const dfsHelper = (index: number) => {
@ -206,11 +189,11 @@ export class Heap<T> {
* Convert the heap to an array.
* @returns An array containing the elements of the heap.
*/
toArray(): T[] {
toArray(): E[] {
return [...this.nodes];
}
getNodes(): T[] {
getNodes(): E[] {
return this.nodes;
}
@ -218,8 +201,8 @@ export class Heap<T> {
* Clone the heap, creating a new heap with the same elements.
* @returns A new Heap instance containing the same elements.
*/
clone(): Heap<T> {
const clonedHeap = new Heap<T>(this.comparator);
clone(): Heap<E> {
const clonedHeap = new Heap<E>(this.comparator);
clonedHeap.nodes = [...this.nodes];
return clonedHeap;
}
@ -228,8 +211,8 @@ export class Heap<T> {
* Sort the elements in the heap and return them as an array.
* @returns An array containing the elements sorted in ascending order.
*/
sort(): T[] {
const visitedNode: T[] = [];
sort(): E[] {
const visitedNode: E[] = [];
const cloned = this.clone();
while (cloned.size !== 0) {
const top = cloned.poll();
@ -244,8 +227,8 @@ export class Heap<T> {
* @param comparator - Comparison function.
* @returns A new Heap instance.
*/
static heapify<T>(nodes: T[], comparator: CompareFunction<T>): Heap<T> {
const binaryHeap = new Heap<T>(comparator);
static heapify<E>(nodes: E[], comparator: CompareFunction<E>): Heap<E> {
const binaryHeap = new Heap<E>(comparator);
binaryHeap.nodes = [...nodes];
binaryHeap.fix(); // Fix heap properties
return binaryHeap;

View file

@ -9,9 +9,9 @@
import {Heap} from './heap';
import type {CompareFunction} from '../../types';
export class MaxHeap<T = any> extends Heap<T> {
export class MaxHeap<E = any> extends Heap<E> {
constructor(
comparator: CompareFunction<T> = (a: T, b: T) => {
comparator: CompareFunction<E> = (a: E, b: E) => {
if (!(typeof a === 'number' && typeof b === 'number')) {
throw new Error('The a, b params of compare function must be number');
} else {

View file

@ -9,9 +9,9 @@
import {Heap} from './heap';
import type {CompareFunction} from '../../types';
export class MinHeap<T = any> extends Heap<T> {
export class MinHeap<E = any> extends Heap<E> {
constructor(
comparator: CompareFunction<T> = (a: T, b: T) => {
comparator: CompareFunction<E> = (a: E, b: E) => {
if (!(typeof a === 'number' && typeof b === 'number')) {
throw new Error('The a, b params of compare function must be number');
} else {

View file

@ -8,9 +8,9 @@
import {PriorityQueue} from './priority-queue';
import type {CompareFunction} from '../../types';
export class MaxPriorityQueue<T = any> extends PriorityQueue<T> {
export class MaxPriorityQueue<E = any> extends PriorityQueue<E> {
constructor(
compare: CompareFunction<T> = (a: T, b: T) => {
compare: CompareFunction<E> = (a: E, b: E) => {
if (!(typeof a === 'number' && typeof b === 'number')) {
throw new Error('The a, b params of compare function must be number');
} else {

View file

@ -8,9 +8,9 @@
import {PriorityQueue} from './priority-queue';
import type {CompareFunction} from '../../types';
export class MinPriorityQueue<T = any> extends PriorityQueue<T> {
export class MinPriorityQueue<E = any> extends PriorityQueue<E> {
constructor(
compare: CompareFunction<T> = (a: T, b: T) => {
compare: CompareFunction<E> = (a: E, b: E) => {
if (!(typeof a === 'number' && typeof b === 'number')) {
throw new Error('The a, b params of compare function must be number');
} else {

View file

@ -9,8 +9,8 @@
import {Heap} from '../heap';
import {CompareFunction} from '../../types';
export class PriorityQueue<T> extends Heap<T> {
constructor(comparator: CompareFunction<T>) {
export class PriorityQueue<E> extends Heap<E> {
constructor(comparator: CompareFunction<E>) {
super(comparator);
}
}

View file

@ -45,5 +45,5 @@ export type AbstractBinaryTreeNodeProperties<N extends AbstractBinaryTreeNode<N[
export type AbstractBinaryTreeNodeNested<T> = AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;
export type AbstractBinaryTreeOptions = {
loopType?: LoopType
};

View file

@ -1,5 +1,5 @@
import {BinaryTreeNode} from '../../data-structures/binary-tree';
import {AbstractBinaryTreeOptions} from './abstract-binary-tree';
import {AbstractBinaryTreeOptions, LoopType} from './abstract-binary-tree';
export type BinaryTreeNodeNested<T> = BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type BinaryTreeOptions = AbstractBinaryTreeOptions & {}
export type BinaryTreeOptions = AbstractBinaryTreeOptions & { loopType?: LoopType }

View file

@ -89,7 +89,8 @@ describe('MaxPriorityQueue Performance Test', () => {
prev = polled;
}
}
expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 50);
const cost = performance.now() - startTime;
expect(cost).toBeLessThan(bigO.LINEAR * 20);
expect(prev).toBeGreaterThan(0);
});

View file

@ -25,7 +25,7 @@ describe('MinPriorityQueue Operation Test', () => {
priorityQueue.add(3);
priorityQueue.add(7);
expect(priorityQueue.leaf()).toBe(7);
expect(priorityQueue.leaf).toBe(7);
});
it('should check if the queue is empty', () => {