[core] Besides Binary Trees and Graphs, access control optimizations have been applied to member variables.

This commit is contained in:
Revone 2023-10-31 10:34:41 +08:00
parent 3009c14c24
commit 1ec5a19172
19 changed files with 303 additions and 373 deletions

View file

@ -60,8 +60,4 @@ export class CoordinateMap<V> extends Map<any, V> {
override delete(key: number[]) {
return super.delete(key.join(this._joint));
}
protected _setJoint(v: string) {
this._joint = v;
}
}

View file

@ -49,8 +49,4 @@ export class CoordinateSet extends Set<any> {
override delete(value: number[]) {
return super.delete(value.join(this._joint));
}
protected _setJoint(v: string) {
this._joint = v;
}
}

View file

@ -38,66 +38,42 @@ export class HashMap<K, V> {
});
}
private _initialCapacity: number;
protected _initialCapacity: number;
get initialCapacity(): number {
return this._initialCapacity;
}
set initialCapacity(value: number) {
this._initialCapacity = value;
}
private _loadFactor: number;
protected _loadFactor: number;
get loadFactor(): number {
return this._loadFactor;
}
set loadFactor(value: number) {
this._loadFactor = value;
}
private _capacityMultiplier: number;
protected _capacityMultiplier: number;
get capacityMultiplier(): number {
return this._capacityMultiplier;
}
set capacityMultiplier(value: number) {
this._capacityMultiplier = value;
}
private _size: number;
protected _size: number;
get size(): number {
return this._size;
}
set size(value: number) {
this._size = value;
}
private _table: Array<Array<[K, V]>>;
protected _table: Array<Array<[K, V]>>;
get table(): Array<Array<[K, V]>> {
return this._table;
}
set table(value: Array<Array<[K, V]>>) {
this._table = value;
}
private _hashFn: HashFunction<K>;
protected _hashFn: HashFunction<K>;
get hashFn(): HashFunction<K> {
return this._hashFn;
}
set hashFn(value: HashFunction<K>) {
this._hashFn = value;
}
set(key: K, value: V): void {
const loadFactor = this.size / this.table.length;
if (loadFactor >= this.loadFactor) {
@ -118,7 +94,7 @@ export class HashMap<K, V> {
}
this.table[index].push([key, value]);
this.size++;
this._size++;
}
get(key: K): V | undefined {
@ -145,7 +121,7 @@ export class HashMap<K, V> {
for (let i = 0; i < this.table[index].length; i++) {
if (this.table[index][i][0] === key) {
this.table[index].splice(i, 1);
this.size--;
this._size--;
// Check if the table needs to be resized down
const loadFactor = this.size / this.table.length;
@ -172,15 +148,15 @@ export class HashMap<K, V> {
}
clear(): void {
this.size = 0;
this.table = new Array(this.initialCapacity);
this._size = 0;
this._table = new Array(this.initialCapacity);
}
isEmpty(): boolean {
return this.size === 0;
}
private _hash(key: K): number {
protected _hash(key: K): number {
return this._hashFn(key);
}
@ -190,7 +166,7 @@ export class HashMap<K, V> {
* @param {number} newCapacity - The newCapacity parameter is the desired capacity for the resized table. It represents
* the number of buckets that the new table should have.
*/
private resizeTable(newCapacity: number): void {
protected resizeTable(newCapacity: number): void {
const newTable = new Array(newCapacity);
for (const bucket of this._table) {
// Note that this is this._table

View file

@ -21,8 +21,8 @@ export class HashTableNode<K, V> {
import {HashFunction} from '../../types';
export class HashTable<K, V> {
private static readonly DEFAULT_CAPACITY = 16;
private static readonly LOAD_FACTOR = 0.75;
protected static readonly DEFAULT_CAPACITY = 16;
protected static readonly LOAD_FACTOR = 0.75;
constructor(capacity: number = HashTable.DEFAULT_CAPACITY, hashFn?: HashFunction<K>) {
this._hashFn = hashFn || this._defaultHashFn;
@ -31,42 +31,30 @@ export class HashTable<K, V> {
this._buckets = new Array<HashTableNode<K, V> | null>(this._capacity).fill(null);
}
private _capacity: number;
protected _capacity: number;
get capacity(): number {
return this._capacity;
}
set capacity(value: number) {
this._capacity = value;
}
private _size: number;
protected _size: number;
get size(): number {
return this._size;
}
private _buckets: Array<HashTableNode<K, V> | null>;
protected _buckets: Array<HashTableNode<K, V> | null>;
get buckets(): Array<HashTableNode<K, V> | null> {
return this._buckets;
}
set buckets(value: Array<HashTableNode<K, V> | null>) {
this._buckets = value;
}
private _hashFn: HashFunction<K>;
protected _hashFn: HashFunction<K>;
get hashFn(): HashFunction<K> {
return this._hashFn;
}
set hashFn(value: HashFunction<K>) {
this._hashFn = value;
}
/**
* The set function adds a key-value pair to the hash table, handling collisions and resizing if necessary.
* @param {K} key - The key parameter represents the key of the key-value pair that you want to insert into the hash

View file

@ -8,17 +8,26 @@
import type {Comparator, DFSOrderPattern} from '../../types';
export class Heap<E = any> {
protected nodes: E[] = [];
protected readonly comparator: Comparator<E>;
constructor(options: {comparator: Comparator<E>; nodes?: E[]}) {
this.comparator = options.comparator;
this._comparator = options.comparator;
if (options.nodes && options.nodes.length > 0) {
this.nodes = options.nodes;
this._nodes = options.nodes;
this.fix();
}
}
protected _nodes: E[] = [];
get nodes(): E[] {
return this._nodes;
}
protected _comparator: Comparator<E>;
get comparator(): Comparator<E> {
return this._comparator;
}
/**
* Get the size (number of elements) of the heap.
*/
@ -110,7 +119,7 @@ export class Heap<E = any> {
* Reset the nodes of the heap. Make the nodes empty.
*/
clear() {
this.nodes = [];
this._nodes = [];
}
/**
@ -118,7 +127,7 @@ export class Heap<E = any> {
* @param nodes
*/
refill(nodes: E[]) {
this.nodes = nodes;
this._nodes = nodes;
this.fix();
}
@ -181,7 +190,7 @@ export class Heap<E = any> {
*/
clone(): Heap<E> {
const clonedHeap = new Heap<E>({comparator: this.comparator});
clonedHeap.nodes = [...this.nodes];
clonedHeap._nodes = [...this.nodes];
return clonedHeap;
}
@ -268,28 +277,47 @@ export class FibonacciHeapNode<E> {
}
export class FibonacciHeap<E> {
root?: FibonacciHeapNode<E>;
size = 0;
protected min?: FibonacciHeapNode<E>;
protected readonly comparator: Comparator<E>;
constructor(comparator?: Comparator<E>) {
this.clear();
this.comparator = comparator || this.defaultComparator;
this._comparator = comparator || this.defaultComparator;
if (typeof this.comparator !== 'function') {
throw new Error('FibonacciHeap constructor: given comparator should be a function.');
}
}
protected _root?: FibonacciHeapNode<E>;
get root(): FibonacciHeapNode<E> | undefined {
return this._root;
}
protected _size = 0;
get size(): number {
return this._size;
}
protected _min?: FibonacciHeapNode<E>;
get min(): FibonacciHeapNode<E> | undefined {
return this._min;
}
protected _comparator: Comparator<E>;
get comparator(): Comparator<E> {
return this._comparator;
}
/**
* Get the size (number of elements) of the heap.
* @returns {number} The size of the heap. Returns 0 if the heap is empty. Returns -1 if the heap is invalid.
*/
clear(): void {
this.root = undefined;
this.min = undefined;
this.size = 0;
this._root = undefined;
this._min = undefined;
this._size = 0;
}
/**
@ -315,10 +343,10 @@ export class FibonacciHeap<E> {
this.mergeWithRoot(node);
if (!this.min || this.comparator(node.element, this.min.element) <= 0) {
this.min = node;
this._min = node;
}
this.size++;
this._size++;
return this;
}
@ -405,14 +433,14 @@ export class FibonacciHeap<E> {
this.removeFromRoot(z);
if (z === z.right) {
this.min = undefined;
this.root = undefined;
this._min = undefined;
this._root = undefined;
} else {
this.min = z.right;
this._min = z.right;
this.consolidate();
}
this.size--;
this._size--;
return z.element;
}
@ -444,11 +472,11 @@ export class FibonacciHeap<E> {
// Update the minimum node
if (!this.min || (heapToMerge.min && this.comparator(heapToMerge.min.element, this.min.element) < 0)) {
this.min = heapToMerge.min;
this._min = heapToMerge.min;
}
// Update the size
this.size += heapToMerge.size;
this._size += heapToMerge.size;
// Clear the heap that was merged
heapToMerge.clear();
@ -481,7 +509,7 @@ export class FibonacciHeap<E> {
*/
protected mergeWithRoot(node: FibonacciHeapNode<E>): void {
if (!this.root) {
this.root = node;
this._root = node;
} else {
node.right = this.root.right;
node.left = this.root;
@ -497,7 +525,7 @@ export class FibonacciHeap<E> {
* @protected
*/
protected removeFromRoot(node: FibonacciHeapNode<E>): void {
if (this.root === node) this.root = node.right;
if (this.root === node) this._root = node.right;
if (node.left) node.left.right = node.right;
if (node.right) node.right.left = node.left;
}
@ -554,7 +582,7 @@ export class FibonacciHeap<E> {
for (let i = 0; i < this.size; i++) {
if (A[i] && this.comparator(A[i]!.element, this.min!.element) <= 0) {
this.min = A[i]!;
this._min = A[i]!;
}
}
}

View file

@ -6,45 +6,19 @@
* @license MIT License
*/
export class DoublyLinkedListNode<E = any> {
value: E;
next: DoublyLinkedListNode<E> | null;
prev: DoublyLinkedListNode<E> | null;
/**
* The constructor function initializes the value, next, and previous properties of an object.
* @param {E} value - The "value" parameter is the value that will be stored in the node. It can be of any data type, as it
* is defined as a generic type "E".
*/
constructor(value: E) {
this._value = value;
this._next = null;
this._prev = null;
}
private _value: E;
get value(): E {
return this._value;
}
set value(value: E) {
this._value = value;
}
private _next: DoublyLinkedListNode<E> | null;
get next(): DoublyLinkedListNode<E> | null {
return this._next;
}
set next(value: DoublyLinkedListNode<E> | null) {
this._next = value;
}
private _prev: DoublyLinkedListNode<E> | null;
get prev(): DoublyLinkedListNode<E> | null {
return this._prev;
}
set prev(value: DoublyLinkedListNode<E> | null) {
this._prev = value;
this.value = value;
this.next = null;
this.prev = null;
}
}
@ -58,27 +32,19 @@ export class DoublyLinkedList<E = any> {
this._length = 0;
}
private _head: DoublyLinkedListNode<E> | null;
protected _head: DoublyLinkedListNode<E> | null;
get head(): DoublyLinkedListNode<E> | null {
return this._head;
}
set head(value: DoublyLinkedListNode<E> | null) {
this._head = value;
}
private _tail: DoublyLinkedListNode<E> | null;
protected _tail: DoublyLinkedListNode<E> | null;
get tail(): DoublyLinkedListNode<E> | null {
return this._tail;
}
set tail(value: DoublyLinkedListNode<E> | null) {
this._tail = value;
}
private _length: number;
protected _length: number;
get length(): number {
return this._length;
@ -109,12 +75,12 @@ export class DoublyLinkedList<E = any> {
push(value: E): void {
const newNode = new DoublyLinkedListNode(value);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
this._head = newNode;
this._tail = newNode;
} else {
newNode.prev = this.tail;
this.tail!.next = newNode;
this.tail = newNode;
this._tail = newNode;
}
this._length++;
}
@ -136,10 +102,10 @@ export class DoublyLinkedList<E = any> {
if (!this.tail) return undefined;
const removedNode = this.tail;
if (this.head === this.tail) {
this.head = null;
this.tail = null;
this._head = null;
this._tail = null;
} else {
this.tail = removedNode.prev;
this._tail = removedNode.prev;
this.tail!.next = null;
}
this._length--;
@ -164,10 +130,10 @@ export class DoublyLinkedList<E = any> {
if (!this.head) return undefined;
const removedNode = this.head;
if (this.head === this.tail) {
this.head = null;
this.tail = null;
this._head = null;
this._tail = null;
} else {
this.head = removedNode.next;
this._head = removedNode.next;
this.head!.prev = null;
}
this._length--;
@ -191,12 +157,12 @@ export class DoublyLinkedList<E = any> {
unshift(value: E): void {
const newNode = new DoublyLinkedListNode(value);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
this._head = newNode;
this._tail = newNode;
} else {
newNode.next = this.head;
this.head!.prev = newNode;
this.head = newNode;
this._head = newNode;
}
this._length++;
}
@ -338,7 +304,7 @@ export class DoublyLinkedList<E = any> {
newNode.next = existingNode;
existingNode.prev = newNode;
if (existingNode === this.head) {
this.head = newNode;
this._head = newNode;
}
this._length++;
return true;
@ -508,7 +474,7 @@ export class DoublyLinkedList<E = any> {
*/
reverse(): void {
let current = this.head;
[this.head, this.tail] = [this.tail, this.head];
[this._head, this._tail] = [this.tail, this.head];
while (current) {
const next = current.next;
[current.prev, current.next] = [current.next, current.prev];
@ -616,7 +582,7 @@ export class DoublyLinkedList<E = any> {
newNode.prev = existingNode;
existingNode.next = newNode;
if (existingNode === this.tail) {
this.tail = newNode;
this._tail = newNode;
}
this._length++;
return true;

View file

@ -6,34 +6,17 @@
* @license MIT License
*/
export class SinglyLinkedListNode<E = any> {
value: E;
next: SinglyLinkedListNode<E> | null;
/**
* The constructor function initializes an instance of a class with a given value and sets the next property to null.
* @param {E} value - The "value" parameter is of type E, which means it can be any data type. It represents the value that
* will be stored in the node of a linked list.
*/
constructor(value: E) {
this._value = value;
this._next = null;
}
private _value: E;
get value(): E {
return this._value;
}
set value(value: E) {
this._value = value;
}
private _next: SinglyLinkedListNode<E> | null;
get next(): SinglyLinkedListNode<E> | null {
return this._next;
}
set next(value: SinglyLinkedListNode<E> | null) {
this._next = value;
this.value = value;
this.next = null;
}
}
@ -47,27 +30,19 @@ export class SinglyLinkedList<E = any> {
this._length = 0;
}
private _head: SinglyLinkedListNode<E> | null;
protected _head: SinglyLinkedListNode<E> | null;
get head(): SinglyLinkedListNode<E> | null {
return this._head;
}
set head(value: SinglyLinkedListNode<E> | null) {
this._head = value;
}
private _tail: SinglyLinkedListNode<E> | null;
protected _tail: SinglyLinkedListNode<E> | null;
get tail(): SinglyLinkedListNode<E> | null {
return this._tail;
}
set tail(value: SinglyLinkedListNode<E> | null) {
this._tail = value;
}
private _length: number;
protected _length: number;
get length(): number {
return this._length;
@ -95,11 +70,11 @@ export class SinglyLinkedList<E = any> {
push(value: E): void {
const newNode = new SinglyLinkedListNode(value);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
this._head = newNode;
this._tail = newNode;
} else {
this.tail!.next = newNode;
this.tail = newNode;
this._tail = newNode;
}
this._length++;
}
@ -123,8 +98,8 @@ export class SinglyLinkedList<E = any> {
if (!this.head) return undefined;
if (this.head === this.tail) {
const value = this.head.value;
this.head = null;
this.tail = null;
this._head = null;
this._tail = null;
this._length--;
return value;
}
@ -135,7 +110,7 @@ export class SinglyLinkedList<E = any> {
}
const value = this.tail!.value;
current.next = null;
this.tail = current;
this._tail = current;
this._length--;
return value;
}
@ -157,7 +132,7 @@ export class SinglyLinkedList<E = any> {
shift(): E | undefined {
if (!this.head) return undefined;
const removedNode = this.head;
this.head = this.head.next;
this._head = this.head.next;
this._length--;
return removedNode.value;
}
@ -178,11 +153,11 @@ export class SinglyLinkedList<E = any> {
unshift(value: E): void {
const newNode = new SinglyLinkedListNode(value);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
this._head = newNode;
this._tail = newNode;
} else {
newNode.next = this.head;
this.head = newNode;
this._head = newNode;
}
this._length++;
}
@ -267,14 +242,14 @@ export class SinglyLinkedList<E = any> {
while (current) {
if (current.value === value) {
if (prev === null) {
this.head = current.next;
this._head = current.next;
if (current === this.tail) {
this.tail = null;
this._tail = null;
}
} else {
prev.next = current.next;
if (current === this.tail) {
this.tail = prev;
this._tail = prev;
}
}
this._length--;
@ -365,7 +340,7 @@ export class SinglyLinkedList<E = any> {
current = next;
}
[this.head, this.tail] = [this.tail!, this.head!];
[this._head, this._tail] = [this.tail!, this.head!];
}
/**
@ -486,7 +461,7 @@ export class SinglyLinkedList<E = any> {
newNode.next = existingNode.next;
existingNode.next = newNode;
if (existingNode === this.tail) {
this.tail = newNode;
this._tail = newNode;
}
this._length++;
return true;

View file

@ -33,46 +33,30 @@ export class SkipList<K, V> {
this._probability = probability;
}
private _head: SkipListNode<K, V>;
protected _head: SkipListNode<K, V>;
get head(): SkipListNode<K, V> {
return this._head;
}
set head(value: SkipListNode<K, V>) {
this._head = value;
}
private _level: number;
protected _level: number;
get level(): number {
return this._level;
}
set level(value: number) {
this._level = value;
}
private _maxLevel: number;
protected _maxLevel: number;
get maxLevel(): number {
return this._maxLevel;
}
set maxLevel(value: number) {
this._maxLevel = value;
}
private _probability: number;
protected _probability: number;
get probability(): number {
return this._probability;
}
set probability(value: number) {
this._probability = value;
}
/**
* The add function adds a new node with a given key and value to a Skip List data structure.
* @param {K} key - The key parameter represents the key of the node that needs to be added to the skip list.
@ -80,7 +64,7 @@ export class SkipList<K, V> {
* List.
*/
add(key: K, value: V): void {
const newNode = new SkipListNode(key, value, this.randomLevel());
const newNode = new SkipListNode(key, value, this._randomLevel());
const update: SkipListNode<K, V>[] = new Array(this.maxLevel).fill(this.head);
let current = this.head;
@ -97,7 +81,7 @@ export class SkipList<K, V> {
}
if (newNode.forward[0] !== null) {
this.level = Math.max(this.level, newNode.forward.length);
this._level = Math.max(this.level, newNode.forward.length);
}
}
@ -124,6 +108,10 @@ export class SkipList<K, V> {
return undefined;
}
has(key: K): boolean {
return this.get(key) !== undefined;
}
/**
* The `delete` function removes a node with a specific key from a Skip List data structure.
* @param {K} key - The key parameter represents the key of the node that needs to be removed from the skip list.
@ -151,7 +139,7 @@ export class SkipList<K, V> {
update[i].forward[i] = current.forward[i];
}
while (this.level > 0 && this.head.forward[this.level - 1] === null) {
this.level--;
this._level--;
}
return true;
}
@ -160,10 +148,70 @@ export class SkipList<K, V> {
}
/**
* The function "randomLevel" generates a random level based on a given probability and maximum level.
* Get the value of the first element (the smallest element) in the Skip List.
* @returns The value of the first element, or undefined if the Skip List is empty.
*/
getFirst(): V | undefined {
const firstNode = this.head.forward[0];
return firstNode ? firstNode.value : undefined;
}
/**
* Get the value of the last element (the largest element) in the Skip List.
* @returns The value of the last element, or undefined if the Skip List is empty.
*/
getLast(): V | undefined {
let current = this.head;
for (let i = this.level - 1; i >= 0; i--) {
while (current.forward[i]) {
current = current.forward[i];
}
}
return current.value;
}
/**
* Get the value of the first element in the Skip List that is greater than the given key.
* @param key - the given key.
* @returns The value of the first element greater than the given key, or undefined if there is no such element.
*/
higher(key: K): V | undefined {
let current = this.head;
for (let i = this.level - 1; i >= 0; i--) {
while (current.forward[i] && current.forward[i].key <= key) {
current = current.forward[i];
}
}
const nextNode = current.forward[0];
return nextNode ? nextNode.value : undefined;
}
/**
* Get the value of the last element in the Skip List that is less than the given key.
* @param key - the given key.
* @returns The value of the last element less than the given key, or undefined if there is no such element.
*/
lower(key: K): V | undefined {
let current = this.head;
let lastLess = null;
for (let i = this.level - 1; i >= 0; i--) {
while (current.forward[i] && current.forward[i].key < key) {
current = current.forward[i];
}
if (current.key < key) {
lastLess = current;
}
}
return lastLess ? lastLess.value : undefined;
}
/**
* The function "_randomLevel" generates a random level based on a given probability and maximum level.
* @returns the level, which is a number.
*/
private randomLevel(): number {
protected _randomLevel(): number {
let level = 1;
while (Math.random() < this.probability && level < this.maxLevel) {
level++;

View file

@ -19,43 +19,31 @@ export class ObjectDeque<E = number> {
if (capacity !== undefined) this._capacity = capacity;
}
private _nodes: {[key: number]: E} = {};
protected _nodes: {[key: number]: E} = {};
get nodes(): {[p: number]: E} {
return this._nodes;
}
private _capacity = Number.MAX_SAFE_INTEGER;
protected _capacity = Number.MAX_SAFE_INTEGER;
get capacity(): number {
return this._capacity;
}
set capacity(value: number) {
this._capacity = value;
}
private _first = -1;
protected _first = -1;
get first(): number {
return this._first;
}
set first(value: number) {
this._first = value;
}
private _last = -1;
protected _last = -1;
get last(): number {
return this._last;
}
set last(value: number) {
this._last = value;
}
private _size = 0;
protected _size = 0;
get size(): number {
return this._size;
@ -67,14 +55,14 @@ export class ObjectDeque<E = number> {
* structure.
*/
addFirst(value: E) {
if (this._size === 0) {
const mid = Math.floor(this._capacity / 2);
if (this.size === 0) {
const mid = Math.floor(this.capacity / 2);
this._first = mid;
this._last = mid;
} else {
this._first--;
}
this._nodes[this._first] = value;
this.nodes[this.first] = value;
this._size++;
}
@ -83,14 +71,14 @@ export class ObjectDeque<E = number> {
* @param {E} value - The `value` parameter represents the value that you want to add to the end of the data structure.
*/
addLast(value: E) {
if (this._size === 0) {
const mid = Math.floor(this._capacity / 2);
if (this.size === 0) {
const mid = Math.floor(this.capacity / 2);
this._first = mid;
this._last = mid;
} else {
this._last++;
}
this._nodes[this._last] = value;
this.nodes[this.last] = value;
this._size++;
}
@ -99,9 +87,9 @@ export class ObjectDeque<E = number> {
* @returns The value of the first element in the data structure.
*/
popFirst() {
if (!this._size) return;
if (!this.size) return;
const value = this.getFirst();
delete this._nodes[this._first];
delete this.nodes[this.first];
this._first++;
this._size--;
return value;
@ -112,7 +100,7 @@ export class ObjectDeque<E = number> {
* @returns The element at the first position of the `_nodes` array.
*/
getFirst() {
if (this._size) return this._nodes[this._first];
if (this.size) return this.nodes[this.first];
}
/**
@ -120,9 +108,9 @@ export class ObjectDeque<E = number> {
* @returns The value that was removed from the data structure.
*/
popLast() {
if (!this._size) return;
if (!this.size) return;
const value = this.getLast();
delete this._nodes[this._last];
delete this.nodes[this.last];
this._last--;
this._size--;
@ -134,7 +122,7 @@ export class ObjectDeque<E = number> {
* @returns The last element in the array "_nodes" is being returned.
*/
getLast() {
if (this._size) return this._nodes[this._last];
if (this.size) return this.nodes[this.last];
}
/**
@ -145,7 +133,7 @@ export class ObjectDeque<E = number> {
* index, `null` is returned.
*/
get(index: number) {
return this._nodes[this._first + index] || null;
return this.nodes[this.first + index] || null;
}
/**
@ -153,25 +141,20 @@ export class ObjectDeque<E = number> {
* @returns The method is returning a boolean value indicating whether the size of the object is less than or equal to 0.
*/
isEmpty() {
return this._size <= 0;
}
protected _seNodes(value: {[p: number]: E}) {
this._nodes = value;
}
protected _setSize(value: number) {
this._size = value;
return this.size <= 0;
}
}
// O(1) time complexity of obtaining the value
// O(n) time complexity of adding at the beginning and the end
export class ArrayDeque<E> {
get nodes(): E[] {
return this._nodes;
}
protected _nodes: E[] = [];
get size() {
return this._nodes.length;
return this.nodes.length;
}
/**
@ -184,7 +167,7 @@ export class ArrayDeque<E> {
* @returns The return value is the new length of the array after the value has been added.
*/
addLast(value: E) {
return this._nodes.push(value);
return this.nodes.push(value);
}
/**
@ -192,7 +175,7 @@ export class ArrayDeque<E> {
* @returns The method `popLast()` returns the last element of the `_nodes` array, or `null` if the array is empty.
*/
popLast(): E | null {
return this._nodes.pop() ?? null;
return this.nodes.pop() ?? null;
}
/**
@ -201,7 +184,7 @@ export class ArrayDeque<E> {
* empty.
*/
popFirst(): E | null {
return this._nodes.shift() ?? null;
return this.nodes.shift() ?? null;
}
/**
@ -215,7 +198,7 @@ export class ArrayDeque<E> {
* `value` at the beginning.
*/
addFirst(value: E) {
return this._nodes.unshift(value);
return this.nodes.unshift(value);
}
/**
@ -224,7 +207,7 @@ export class ArrayDeque<E> {
* empty, it will return `null`.
*/
getFirst(): E | null {
return this._nodes[0] ?? null;
return this.nodes[0] ?? null;
}
/**
@ -232,7 +215,7 @@ export class ArrayDeque<E> {
* @returns The method `getLast()` returns the last element of the `_nodes` array, or `null` if the array is empty.
*/
getLast(): E | null {
return this._nodes[this._nodes.length - 1] ?? null;
return this.nodes[this.nodes.length - 1] ?? null;
}
/**
@ -247,7 +230,7 @@ export class ArrayDeque<E> {
* will be returned. If the element does not exist (i.e., the index is out of bounds), `null` will be returned.
*/
get(index: number): E | null {
return this._nodes[index] ?? null;
return this.nodes[index] ?? null;
}
/**
@ -259,7 +242,7 @@ export class ArrayDeque<E> {
* @returns The value that is being set at the specified index in the `_nodes` array.
*/
set(index: number, value: E) {
return (this._nodes[index] = value);
return (this.nodes[index] = value);
}
/**
@ -273,7 +256,7 @@ export class ArrayDeque<E> {
* are being removed, an empty array will be returned.
*/
insert(index: number, value: E) {
return this._nodes.splice(index, 0, value);
return this.nodes.splice(index, 0, value);
}
/**
@ -283,7 +266,7 @@ export class ArrayDeque<E> {
* @returns The method is returning an array containing the removed element.
*/
delete(index: number) {
return this._nodes.splice(index, 1);
return this.nodes.splice(index, 1);
}
/**
@ -292,6 +275,6 @@ export class ArrayDeque<E> {
* is 0, indicating that the array is empty. Otherwise, it returns `false`.
*/
isEmpty() {
return this._nodes.length === 0;
return this.nodes.length === 0;
}
}

View file

@ -51,26 +51,18 @@ export class Queue<E = any> {
this._offset = 0;
}
private _nodes: E[];
protected _nodes: E[];
get nodes(): E[] {
return this._nodes;
}
set nodes(value: E[]) {
this._nodes = value;
}
private _offset: number;
protected _offset: number;
get offset(): number {
return this._offset;
}
set offset(value: number) {
this._offset = value;
}
/**
* The size function returns the number of elements in an array.
* @returns {number} The size of the array, which is the difference between the length of the array and the offset.
@ -110,14 +102,14 @@ export class Queue<E = any> {
if (this.size === 0) return undefined;
const first = this.getFirst();
this.offset += 1;
this._offset += 1;
if (this.offset * 2 < this.nodes.length) return first;
// only delete dequeued elements when reaching half size
// to decrease latency of shifting elements.
this.nodes = this.nodes.slice(this.offset);
this.offset = 0;
this._nodes = this.nodes.slice(this.offset);
this._offset = 0;
return first;
}
@ -130,7 +122,6 @@ export class Queue<E = any> {
return this.size > 0 ? this.nodes[this.offset] : undefined;
}
/**
* The `peek` function returns the first element of the array `_nodes` if it exists, otherwise it returns `null`.
* @returns The `peek()` method returns the first element of the data structure, represented by the `_nodes` array at
@ -157,7 +148,7 @@ export class Queue<E = any> {
peekLast(): E | undefined {
return this.getLast();
}
/**
* The enqueue function adds a value to the end of a queue.
* @param {E} value - The value parameter represents the value that you want to add to the queue.
@ -198,8 +189,8 @@ export class Queue<E = any> {
* The clear function resets the nodes array and offset to their initial values.
*/
clear(): void {
this.nodes = [];
this.offset = 0;
this._nodes = [];
this._offset = 0;
}
/**

View file

@ -4,6 +4,9 @@
* @class
*/
export class Stack<E = any> {
get elements(): E[] {
return this._elements;
}
protected _elements: E[];
/**
@ -31,7 +34,7 @@ export class Stack<E = any> {
* @returns A boolean value indicating whether the `_elements` array is empty or not.
*/
isEmpty(): boolean {
return this._elements.length === 0;
return this.elements.length === 0;
}
/**
@ -39,7 +42,7 @@ export class Stack<E = any> {
* @returns The size of the elements array.
*/
size(): number {
return this._elements.length;
return this.elements.length;
}
/**
@ -49,7 +52,7 @@ export class Stack<E = any> {
peek(): E | null {
if (this.isEmpty()) return null;
return this._elements[this._elements.length - 1];
return this.elements[this.elements.length - 1];
}
/**
@ -58,7 +61,7 @@ export class Stack<E = any> {
* @returns The `push` method is returning the updated `Stack<E>` object.
*/
push(element: E): Stack<E> {
this._elements.push(element);
this.elements.push(element);
return this;
}
@ -70,7 +73,7 @@ export class Stack<E = any> {
pop(): E | null {
if (this.isEmpty()) return null;
return this._elements.pop() || null;
return this.elements.pop() || null;
}
/**
@ -78,7 +81,7 @@ export class Stack<E = any> {
* @returns An array of type E.
*/
toArray(): E[] {
return this._elements.slice();
return this.elements.slice();
}
/**
@ -93,6 +96,6 @@ export class Stack<E = any> {
* @returns The `clone()` method is returning a new `Stack` object with a copy of the `_elements` array.
*/
clone(): Stack<E> {
return new Stack(this._elements.slice());
return new Stack(this.elements.slice());
}
}

View file

@ -1,39 +1,15 @@
export class TreeNode<V = any> {
constructor(key: string, value?: V, children?: TreeNode<V>[]) {
this._key = key;
this._value = value || undefined;
this._children = children || [];
this.key = key;
this.value = value || undefined;
this.children = children || [];
}
private _key: string;
key: string;
get key(): string {
return this._key;
}
value?: V | undefined;
set key(value: string) {
this._key = value;
}
private _value?: V | undefined;
get value(): V | undefined {
return this._value;
}
set value(value: V | undefined) {
this._value = value;
}
private _children?: TreeNode<V>[] | undefined;
get children(): TreeNode<V>[] | undefined {
return this._children;
}
set children(value: TreeNode<V>[] | undefined) {
this._children = value;
}
children?: TreeNode<V>[] | undefined;
addChildren(children: TreeNode<V> | TreeNode<V>[]) {
if (!this.children) {

View file

@ -12,47 +12,26 @@
*/
export class TrieNode {
constructor(key: string) {
this._key = key;
this._isEnd = false;
this._children = new Map<string, TrieNode>();
this.key = key;
this.isEnd = false;
this.children = new Map<string, TrieNode>();
}
private _key;
key: string;
get key(): string {
return this._key;
}
children: Map<string, TrieNode>;
set key(v: string) {
this._key = v;
}
protected _children: Map<string, TrieNode>;
get children(): Map<string, TrieNode> {
return this._children;
}
set children(v: Map<string, TrieNode>) {
this._children = v;
}
protected _isEnd: boolean;
get isEnd(): boolean {
return this._isEnd;
}
set isEnd(v: boolean) {
this._isEnd = v;
}
isEnd: boolean;
}
/**
* Trie represents a Trie data structure. It provides basic Trie operations and additional methods.
*/
export class Trie {
private readonly _caseSensitive: boolean;
get caseSensitive(): boolean {
return this._caseSensitive;
}
protected _caseSensitive: boolean;
constructor(words?: string[], caseSensitive = true) {
this._root = new TrieNode('');
@ -70,10 +49,6 @@ export class Trie {
return this._root;
}
set root(v: TrieNode) {
this._root = v;
}
/**
* Add a word to the Trie structure.
* @param {string} word - The word to add.
@ -277,7 +252,7 @@ export class Trie {
return words;
}
private _caseProcess(str: string) {
protected _caseProcess(str: string) {
if (!this._caseSensitive) {
str = str.toLowerCase(); // Convert str to lowercase if case-insensitive
}

View file

@ -54,12 +54,12 @@ class MyGraph<
}
edgesOf(vertexOrKey: VO | VertexKey): EO[] {
const a = typeof vertexOrKey === "string" ? vertexOrKey : "a";
const a = typeof vertexOrKey === 'string' ? vertexOrKey : 'a';
return [new MyEdge(a, 'b') as EO];
}
getNeighbors(vertexOrKey: VO | VertexKey): VO[] {
const a = typeof vertexOrKey === "string" ? vertexOrKey : "a";
const a = typeof vertexOrKey === 'string' ? vertexOrKey : 'a';
return [new MyVertex(a, 'b') as VO];
}
@ -75,8 +75,7 @@ class MyGraph<
describe('AbstractGraph Operation Test', () => {
const myGraph: MyGraph<number, string> = new MyGraph<number, string>();
beforeEach(() => {
});
beforeEach(() => {});
it('should edge cases', function () {
myGraph.addVertex('A', 1);
myGraph.addVertex('B', 2);

View file

@ -57,7 +57,7 @@ describe('CoordinateMap', () => {
class MyCoordinateMap<V = any> extends CoordinateMap<V> {
constructor(joint?: string) {
super(joint);
this._setJoint((joint += '-'));
this._joint = joint += '-';
}
}

View file

@ -44,7 +44,7 @@ describe('MyCoordinateSet', () => {
class MyCoordinateSet extends CoordinateSet {
constructor(joint?: string) {
super(joint);
this._setJoint((joint += '-'));
this._joint = joint += '-';
}
}

View file

@ -28,7 +28,6 @@ describe('HashMap', () => {
it('should handle key collisions', () => {
// Force a collision by setting two different keys to the same bucket
hashMap.hashFn = () => 0; // Override hash function to return the same index
hashMap.set('key1', 1);
hashMap.set('key2', 2);

View file

@ -15,9 +15,9 @@ describe('HashNode', () => {
describe('HashTable', () => {
it('should initialize with default capacity', () => {
const hashTable = new HashTable<string, string>();
hashTable.capacity = hashTable.capacity;
hashTable.buckets = hashTable.buckets;
hashTable.hashFn = hashTable.hashFn;
expect(hashTable.capacity).toBe(16);
expect(hashTable.buckets).toEqual(new Array(16).fill(null));
expect(hashTable.hashFn('a')).toBe(6);
expect(hashTable.capacity).toBe(16);
expect(hashTable.size).toBe(0);
expect(hashTable.buckets.length).toBe(16);

View file

@ -53,3 +53,34 @@ describe('SkipList', () => {
expect(skipList.get(4)).toBe('Four');
});
});
describe('SkipList', () => {
let skipList: SkipList<number, string>;
beforeEach(() => {
skipList = new SkipList();
skipList.add(1, 'One');
skipList.add(2, 'Two');
skipList.add(3, 'Three');
skipList.add(4, 'Four');
});
test('getFirst() should return the getFirst element', () => {
expect(skipList.getFirst()).toBe('One');
});
test('getLast() should return the getLast element', () => {
expect(skipList.getLast()).toBe('Four');
});
test('higher(key) should return the getFirst element greater than the given key', () => {
expect(skipList.higher(2)).toBe('Three');
expect(skipList.higher(3)).toBe('Four');
expect(skipList.higher(4)).toBeUndefined();
});
test('lower(key) should return the getLast element less than the given key', () => {
expect(skipList.lower(2)).toBe('One');
expect(skipList.lower(1)).toBe(null);
});
});