From 1ec5a19172bab67897a1fae602be5b96c583d14f Mon Sep 17 00:00:00 2001 From: Revone Date: Tue, 31 Oct 2023 10:34:41 +0800 Subject: [PATCH] [core] Besides Binary Trees and Graphs, access control optimizations have been applied to member variables. --- src/data-structures/hash/coordinate-map.ts | 4 - src/data-structures/hash/coordinate-set.ts | 4 - src/data-structures/hash/hash-map.ts | 48 +++------ src/data-structures/hash/hash-table.ts | 24 ++--- src/data-structures/heap/heap.ts | 84 ++++++++++------ .../linked-list/doubly-linked-list.ts | 84 +++++----------- .../linked-list/singly-linked-list.ts | 71 +++++--------- .../linked-list/skip-linked-list.ts | 98 ++++++++++++++----- src/data-structures/queue/deque.ts | 85 +++++++--------- src/data-structures/queue/queue.ts | 25 ++--- src/data-structures/stack/stack.ts | 17 ++-- src/data-structures/tree/tree.ts | 36 ++----- src/data-structures/trie/trie.ts | 47 +++------ .../graph/abstract-graph.test.ts | 7 +- .../hash/coordinate-map.test.ts | 2 +- .../hash/coordinate-set.test.ts | 2 +- .../data-structures/hash/hash-map.test.ts | 1 - .../data-structures/hash/hash-table.test.ts | 6 +- .../linked-list/skip-list.test.ts | 31 ++++++ 19 files changed, 303 insertions(+), 373 deletions(-) diff --git a/src/data-structures/hash/coordinate-map.ts b/src/data-structures/hash/coordinate-map.ts index 64bdff7..02ffd45 100644 --- a/src/data-structures/hash/coordinate-map.ts +++ b/src/data-structures/hash/coordinate-map.ts @@ -60,8 +60,4 @@ export class CoordinateMap extends Map { override delete(key: number[]) { return super.delete(key.join(this._joint)); } - - protected _setJoint(v: string) { - this._joint = v; - } } diff --git a/src/data-structures/hash/coordinate-set.ts b/src/data-structures/hash/coordinate-set.ts index 0584d91..e7437eb 100644 --- a/src/data-structures/hash/coordinate-set.ts +++ b/src/data-structures/hash/coordinate-set.ts @@ -49,8 +49,4 @@ export class CoordinateSet extends Set { override delete(value: number[]) { return super.delete(value.join(this._joint)); } - - protected _setJoint(v: string) { - this._joint = v; - } } diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index f3a5213..9595be5 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -38,66 +38,42 @@ export class HashMap { }); } - 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>; + protected _table: Array>; get table(): Array> { return this._table; } - set table(value: Array>) { - this._table = value; - } - - private _hashFn: HashFunction; + protected _hashFn: HashFunction; get hashFn(): HashFunction { return this._hashFn; } - set hashFn(value: HashFunction) { - 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 { } this.table[index].push([key, value]); - this.size++; + this._size++; } get(key: K): V | undefined { @@ -145,7 +121,7 @@ export class HashMap { 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 { } 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 { * @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 diff --git a/src/data-structures/hash/hash-table.ts b/src/data-structures/hash/hash-table.ts index 26b4ddd..783819f 100644 --- a/src/data-structures/hash/hash-table.ts +++ b/src/data-structures/hash/hash-table.ts @@ -21,8 +21,8 @@ export class HashTableNode { import {HashFunction} from '../../types'; export class HashTable { - 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) { this._hashFn = hashFn || this._defaultHashFn; @@ -31,42 +31,30 @@ export class HashTable { this._buckets = new Array | 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 | null>; + protected _buckets: Array | null>; get buckets(): Array | null> { return this._buckets; } - set buckets(value: Array | null>) { - this._buckets = value; - } - - private _hashFn: HashFunction; + protected _hashFn: HashFunction; get hashFn(): HashFunction { return this._hashFn; } - set hashFn(value: HashFunction) { - 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 diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 4f3fbe6..60d4533 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -8,17 +8,26 @@ import type {Comparator, DFSOrderPattern} from '../../types'; export class Heap { - protected nodes: E[] = []; - protected readonly comparator: Comparator; - constructor(options: {comparator: Comparator; 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; + + get comparator(): Comparator { + return this._comparator; + } + /** * Get the size (number of elements) of the heap. */ @@ -110,7 +119,7 @@ export class Heap { * Reset the nodes of the heap. Make the nodes empty. */ clear() { - this.nodes = []; + this._nodes = []; } /** @@ -118,7 +127,7 @@ export class Heap { * @param nodes */ refill(nodes: E[]) { - this.nodes = nodes; + this._nodes = nodes; this.fix(); } @@ -181,7 +190,7 @@ export class Heap { */ clone(): Heap { const clonedHeap = new Heap({comparator: this.comparator}); - clonedHeap.nodes = [...this.nodes]; + clonedHeap._nodes = [...this.nodes]; return clonedHeap; } @@ -268,28 +277,47 @@ export class FibonacciHeapNode { } export class FibonacciHeap { - root?: FibonacciHeapNode; - size = 0; - protected min?: FibonacciHeapNode; - protected readonly comparator: Comparator; - constructor(comparator?: Comparator) { 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; + + get root(): FibonacciHeapNode | undefined { + return this._root; + } + + protected _size = 0; + + get size(): number { + return this._size; + } + + protected _min?: FibonacciHeapNode; + + get min(): FibonacciHeapNode | undefined { + return this._min; + } + + protected _comparator: Comparator; + + get comparator(): Comparator { + 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 { 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 { 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 { // 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 { */ protected mergeWithRoot(node: FibonacciHeapNode): 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 { * @protected */ protected removeFromRoot(node: FibonacciHeapNode): 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 { 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]!; } } } diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index 6c833bf..119ae71 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -6,45 +6,19 @@ * @license MIT License */ export class DoublyLinkedListNode { + value: E; + next: DoublyLinkedListNode | null; + prev: DoublyLinkedListNode | 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 | null; - - get next(): DoublyLinkedListNode | null { - return this._next; - } - - set next(value: DoublyLinkedListNode | null) { - this._next = value; - } - - private _prev: DoublyLinkedListNode | null; - - get prev(): DoublyLinkedListNode | null { - return this._prev; - } - - set prev(value: DoublyLinkedListNode | null) { - this._prev = value; + this.value = value; + this.next = null; + this.prev = null; } } @@ -58,27 +32,19 @@ export class DoublyLinkedList { this._length = 0; } - private _head: DoublyLinkedListNode | null; + protected _head: DoublyLinkedListNode | null; get head(): DoublyLinkedListNode | null { return this._head; } - set head(value: DoublyLinkedListNode | null) { - this._head = value; - } - - private _tail: DoublyLinkedListNode | null; + protected _tail: DoublyLinkedListNode | null; get tail(): DoublyLinkedListNode | null { return this._tail; } - set tail(value: DoublyLinkedListNode | null) { - this._tail = value; - } - - private _length: number; + protected _length: number; get length(): number { return this._length; @@ -109,12 +75,12 @@ export class DoublyLinkedList { 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 { 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 { 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 { 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 { 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 { */ 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 { newNode.prev = existingNode; existingNode.next = newNode; if (existingNode === this.tail) { - this.tail = newNode; + this._tail = newNode; } this._length++; return true; diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index d9a2818..7c39cf6 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -6,34 +6,17 @@ * @license MIT License */ export class SinglyLinkedListNode { + value: E; + next: SinglyLinkedListNode | 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 | null; - - get next(): SinglyLinkedListNode | null { - return this._next; - } - - set next(value: SinglyLinkedListNode | null) { - this._next = value; + this.value = value; + this.next = null; } } @@ -47,27 +30,19 @@ export class SinglyLinkedList { this._length = 0; } - private _head: SinglyLinkedListNode | null; + protected _head: SinglyLinkedListNode | null; get head(): SinglyLinkedListNode | null { return this._head; } - set head(value: SinglyLinkedListNode | null) { - this._head = value; - } - - private _tail: SinglyLinkedListNode | null; + protected _tail: SinglyLinkedListNode | null; get tail(): SinglyLinkedListNode | null { return this._tail; } - set tail(value: SinglyLinkedListNode | null) { - this._tail = value; - } - - private _length: number; + protected _length: number; get length(): number { return this._length; @@ -95,11 +70,11 @@ export class SinglyLinkedList { 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 { 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 { } 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 { 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 { 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 { 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 { 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 { newNode.next = existingNode.next; existingNode.next = newNode; if (existingNode === this.tail) { - this.tail = newNode; + this._tail = newNode; } this._length++; return true; diff --git a/src/data-structures/linked-list/skip-linked-list.ts b/src/data-structures/linked-list/skip-linked-list.ts index 59842ae..0514863 100644 --- a/src/data-structures/linked-list/skip-linked-list.ts +++ b/src/data-structures/linked-list/skip-linked-list.ts @@ -33,46 +33,30 @@ export class SkipList { this._probability = probability; } - private _head: SkipListNode; + protected _head: SkipListNode; get head(): SkipListNode { return this._head; } - set head(value: SkipListNode) { - 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 { * 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[] = new Array(this.maxLevel).fill(this.head); let current = this.head; @@ -97,7 +81,7 @@ export class SkipList { } 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 { 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 { 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 { } /** - * 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++; diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 8d6490a..3dc8c58 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -19,43 +19,31 @@ export class ObjectDeque { 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 { * 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 { * @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 { * @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 { * @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 { * @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 { * @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 { * 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 { * @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 { + 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 { * @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 { * @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 { * empty. */ popFirst(): E | null { - return this._nodes.shift() ?? null; + return this.nodes.shift() ?? null; } /** @@ -215,7 +198,7 @@ export class ArrayDeque { * `value` at the beginning. */ addFirst(value: E) { - return this._nodes.unshift(value); + return this.nodes.unshift(value); } /** @@ -224,7 +207,7 @@ export class ArrayDeque { * 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 { * @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 { * 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 { * @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 { * 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 { * @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 { * is 0, indicating that the array is empty. Otherwise, it returns `false`. */ isEmpty() { - return this._nodes.length === 0; + return this.nodes.length === 0; } } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index bc3a78c..9991f38 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -51,26 +51,18 @@ export class Queue { 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 { 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 { 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 { 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 { * 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; } /** diff --git a/src/data-structures/stack/stack.ts b/src/data-structures/stack/stack.ts index 8656648..0b2bfce 100644 --- a/src/data-structures/stack/stack.ts +++ b/src/data-structures/stack/stack.ts @@ -4,6 +4,9 @@ * @class */ export class Stack { + get elements(): E[] { + return this._elements; + } protected _elements: E[]; /** @@ -31,7 +34,7 @@ export class Stack { * @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 { * @returns The size of the elements array. */ size(): number { - return this._elements.length; + return this.elements.length; } /** @@ -49,7 +52,7 @@ export class Stack { 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 { * @returns The `push` method is returning the updated `Stack` object. */ push(element: E): Stack { - this._elements.push(element); + this.elements.push(element); return this; } @@ -70,7 +73,7 @@ export class Stack { 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 { * @returns An array of type E. */ toArray(): E[] { - return this._elements.slice(); + return this.elements.slice(); } /** @@ -93,6 +96,6 @@ export class Stack { * @returns The `clone()` method is returning a new `Stack` object with a copy of the `_elements` array. */ clone(): Stack { - return new Stack(this._elements.slice()); + return new Stack(this.elements.slice()); } } diff --git a/src/data-structures/tree/tree.ts b/src/data-structures/tree/tree.ts index b2167d6..729365a 100644 --- a/src/data-structures/tree/tree.ts +++ b/src/data-structures/tree/tree.ts @@ -1,39 +1,15 @@ export class TreeNode { constructor(key: string, value?: V, children?: TreeNode[]) { - 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[] | undefined; - - get children(): TreeNode[] | undefined { - return this._children; - } - - set children(value: TreeNode[] | undefined) { - this._children = value; - } + children?: TreeNode[] | undefined; addChildren(children: TreeNode | TreeNode[]) { if (!this.children) { diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index 780b562..08bd374 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -12,47 +12,26 @@ */ export class TrieNode { constructor(key: string) { - this._key = key; - this._isEnd = false; - this._children = new Map(); + this.key = key; + this.isEnd = false; + this.children = new Map(); } - private _key; + key: string; - get key(): string { - return this._key; - } + children: Map; - set key(v: string) { - this._key = v; - } - - protected _children: Map; - - get children(): Map { - return this._children; - } - - set children(v: Map) { - 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 } diff --git a/test/unit/data-structures/graph/abstract-graph.test.ts b/test/unit/data-structures/graph/abstract-graph.test.ts index b9dbefd..a9f6774 100644 --- a/test/unit/data-structures/graph/abstract-graph.test.ts +++ b/test/unit/data-structures/graph/abstract-graph.test.ts @@ -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 = new MyGraph(); - beforeEach(() => { - }); + beforeEach(() => {}); it('should edge cases', function () { myGraph.addVertex('A', 1); myGraph.addVertex('B', 2); diff --git a/test/unit/data-structures/hash/coordinate-map.test.ts b/test/unit/data-structures/hash/coordinate-map.test.ts index 672b2b7..2601d13 100644 --- a/test/unit/data-structures/hash/coordinate-map.test.ts +++ b/test/unit/data-structures/hash/coordinate-map.test.ts @@ -57,7 +57,7 @@ describe('CoordinateMap', () => { class MyCoordinateMap extends CoordinateMap { constructor(joint?: string) { super(joint); - this._setJoint((joint += '-')); + this._joint = joint += '-'; } } diff --git a/test/unit/data-structures/hash/coordinate-set.test.ts b/test/unit/data-structures/hash/coordinate-set.test.ts index a05ec04..eb0a3ca 100644 --- a/test/unit/data-structures/hash/coordinate-set.test.ts +++ b/test/unit/data-structures/hash/coordinate-set.test.ts @@ -44,7 +44,7 @@ describe('MyCoordinateSet', () => { class MyCoordinateSet extends CoordinateSet { constructor(joint?: string) { super(joint); - this._setJoint((joint += '-')); + this._joint = joint += '-'; } } diff --git a/test/unit/data-structures/hash/hash-map.test.ts b/test/unit/data-structures/hash/hash-map.test.ts index 6cb66e2..de3e2c1 100644 --- a/test/unit/data-structures/hash/hash-map.test.ts +++ b/test/unit/data-structures/hash/hash-map.test.ts @@ -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); diff --git a/test/unit/data-structures/hash/hash-table.test.ts b/test/unit/data-structures/hash/hash-table.test.ts index 284eb5f..b786774 100644 --- a/test/unit/data-structures/hash/hash-table.test.ts +++ b/test/unit/data-structures/hash/hash-table.test.ts @@ -15,9 +15,9 @@ describe('HashNode', () => { describe('HashTable', () => { it('should initialize with default capacity', () => { const hashTable = new HashTable(); - 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); diff --git a/test/unit/data-structures/linked-list/skip-list.test.ts b/test/unit/data-structures/linked-list/skip-list.test.ts index 24c041e..e6d189b 100644 --- a/test/unit/data-structures/linked-list/skip-list.test.ts +++ b/test/unit/data-structures/linked-list/skip-list.test.ts @@ -53,3 +53,34 @@ describe('SkipList', () => { expect(skipList.get(4)).toBe('Four'); }); }); + +describe('SkipList', () => { + let skipList: SkipList; + + 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); + }); +});