refactor: In Linked List data structures, only use 'undefined' and abandon the design where both 'null' and 'undefined' coexist.

This commit is contained in:
Revone 2023-11-27 09:31:11 +08:00
parent 7da4f8add9
commit e89509eb34
6 changed files with 105 additions and 105 deletions

View file

@ -7,8 +7,8 @@
*/
export class DoublyLinkedListNode<E = any> {
value: E;
next: DoublyLinkedListNode<E> | null;
prev: DoublyLinkedListNode<E> | null;
next: DoublyLinkedListNode<E> | undefined;
prev: DoublyLinkedListNode<E> | undefined;
/**
* The constructor function initializes the value, next, and previous properties of an object.
@ -17,8 +17,8 @@ export class DoublyLinkedListNode<E = any> {
*/
constructor(value: E) {
this.value = value;
this.next = null;
this.prev = null;
this.next = undefined;
this.prev = undefined;
}
}
@ -27,8 +27,8 @@ export class DoublyLinkedList<E = any> {
* The constructor initializes the linked list with an empty head, tail, and length.
*/
constructor(elements?: Iterable<E>) {
this._head = null;
this._tail = null;
this._head = undefined;
this._tail = undefined;
this._length = 0;
if (elements) {
for (const el of elements) {
@ -37,15 +37,15 @@ export class DoublyLinkedList<E = any> {
}
}
protected _head: DoublyLinkedListNode<E> | null;
protected _head: DoublyLinkedListNode<E> | undefined;
get head(): DoublyLinkedListNode<E> | null {
get head(): DoublyLinkedListNode<E> | undefined {
return this._head;
}
protected _tail: DoublyLinkedListNode<E> | null;
protected _tail: DoublyLinkedListNode<E> | undefined;
get tail(): DoublyLinkedListNode<E> | null {
get tail(): DoublyLinkedListNode<E> | undefined {
return this._tail;
}
@ -133,17 +133,17 @@ export class DoublyLinkedList<E = any> {
*
* The `pop()` function removes and returns the value of the last node in a doubly linked list.
* @returns The method is returning the value of the removed node (removedNode.value) if the list is not empty. If the
* list is empty, it returns null.
* list is empty, it returns undefined.
*/
pop(): E | undefined {
if (!this.tail) return undefined;
const removedNode = this.tail;
if (this.head === this.tail) {
this._head = null;
this._tail = null;
this._head = undefined;
this._tail = undefined;
} else {
this._tail = removedNode.prev;
this.tail!.next = null;
this.tail!.next = undefined;
}
this._length--;
return removedNode.value;
@ -160,7 +160,7 @@ export class DoublyLinkedList<E = any> {
*
* The `popLast()` function removes and returns the value of the last node in a doubly linked list.
* @returns The method is returning the value of the removed node (removedNode.value) if the list is not empty. If the
* list is empty, it returns null.
* list is empty, it returns undefined.
*/
popLast(): E | undefined {
return this.pop();
@ -183,11 +183,11 @@ 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 = undefined;
this._tail = undefined;
} else {
this._head = removedNode.next;
this.head!.prev = null;
this.head!.prev = undefined;
}
this._length--;
return removedNode.value;
@ -262,8 +262,8 @@ export class DoublyLinkedList<E = any> {
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*
* The `getFirst` function returns the first node in a doubly linked list, or null if the list is empty.
* @returns The method `getFirst()` returns the first node of the doubly linked list, or `null` if the list is empty.
* The `getFirst` function returns the first node in a doubly linked list, or undefined if the list is empty.
* @returns The method `getFirst()` returns the first node of the doubly linked list, or `undefined` if the list is empty.
*/
getFirst(): E | undefined {
return this.head?.value;
@ -278,8 +278,8 @@ export class DoublyLinkedList<E = any> {
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*
* The `getLast` function returns the last node in a doubly linked list, or null if the list is empty.
* @returns The method `getLast()` returns the last node of the doubly linked list, or `null` if the list is empty.
* The `getLast` function returns the last node in a doubly linked list, or undefined if the list is empty.
* @returns The method `getLast()` returns the last node of the doubly linked list, or `undefined` if the list is empty.
*/
getLast(): E | undefined {
return this.tail?.value;
@ -294,11 +294,11 @@ export class DoublyLinkedList<E = any> {
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*
* The `getAt` function returns the value at a specified index in a linked list, or null if the index is out of bounds.
* The `getAt` function returns the value at a specified index in a linked list, or undefined if the index is out of bounds.
* @param {number} index - The index parameter is a number that represents the position of the element we want to
* retrieve from the list.
* @returns The method is returning the value at the specified index in the linked list. If the index is out of bounds
* or the linked list is empty, it will return null.
* or the linked list is empty, it will return undefined.
*/
getAt(index: number): E | undefined {
if (index < 0 || index >= this.length) return undefined;
@ -318,15 +318,15 @@ export class DoublyLinkedList<E = any> {
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*
* The function `getNodeAt` returns the node at a given index in a doubly linked list, or null if the index is out of
* The function `getNodeAt` returns the node at a given index in a doubly linked list, or undefined if the index is out of
* range.
* @param {number} index - The `index` parameter is a number that represents the position of the node we want to
* retrieve from the doubly linked list. It indicates the zero-based index of the node we want to access.
* @returns The method `getNodeAt(index: number)` returns a `DoublyLinkedListNode<E>` object if the index is within the
* valid range of the linked list, otherwise it returns `null`.
* valid range of the linked list, otherwise it returns `undefined`.
*/
getNodeAt(index: number): DoublyLinkedListNode<E> | null {
if (index < 0 || index >= this.length) return null;
getNodeAt(index: number): DoublyLinkedListNode<E> | undefined {
if (index < 0 || index >= this.length) return undefined;
let current = this.head;
for (let i = 0; i < index; i++) {
current = current!.next;
@ -344,12 +344,12 @@ export class DoublyLinkedList<E = any> {
* Space Complexity: O(1)
*
* The function `findNodeByValue` searches for a node with a specific value in a doubly linked list and returns the
* node if found, otherwise it returns null.
* node if found, otherwise it returns undefined.
* @param {E} value - The `value` parameter is the value that we want to search for in the doubly linked list.
* @returns The function `findNodeByValue` returns a `DoublyLinkedListNode<E>` if a node with the specified value `value`
* is found in the linked list. If no such node is found, it returns `null`.
* is found in the linked list. If no such node is found, it returns `undefined`.
*/
getNode(value: E | null): DoublyLinkedListNode<E> | null {
getNode(value: E | undefined): DoublyLinkedListNode<E> | undefined {
let current = this.head;
while (current) {
@ -359,7 +359,7 @@ export class DoublyLinkedList<E = any> {
current = current.next;
}
return null;
return undefined;
}
/**
@ -502,7 +502,7 @@ export class DoublyLinkedList<E = any> {
* The `deleteAt` function removes an element at a specified index from a linked list and returns the removed element.
* @param {number} index - The index parameter represents the position of the element that needs to be deleted in the
* data structure. It is of type number.
* @returns The method `deleteAt` returns the value of the node that was deleted, or `null` if the index is out of
* @returns The method `deleteAt` returns the value of the node that was deleted, or `undefined` if the index is out of
* bounds.
*/
deleteAt(index: number): E | undefined {
@ -534,8 +534,8 @@ export class DoublyLinkedList<E = any> {
* @returns The `delete` method returns a boolean value. It returns `true` if the value or node was successfully
* deleted from the doubly linked list, and `false` if the value or node was not found in the list.
*/
delete(valOrNode: E | DoublyLinkedListNode<E> | null): boolean {
let node: DoublyLinkedListNode<E> | null;
delete(valOrNode: E | DoublyLinkedListNode<E> | undefined): boolean {
let node: DoublyLinkedListNode<E> | undefined;
if (valOrNode instanceof DoublyLinkedListNode) {
node = valOrNode;
@ -569,11 +569,11 @@ export class DoublyLinkedList<E = any> {
}
/**
* The `clear` function resets the linked list by setting the head, tail, and length to null and 0 respectively.
* The `clear` function resets the linked list by setting the head, tail, and length to undefined and 0 respectively.
*/
clear(): void {
this._head = null;
this._tail = null;
this._head = undefined;
this._tail = undefined;
this._length = 0;
}
@ -590,9 +590,9 @@ export class DoublyLinkedList<E = any> {
* @param callback - A function that takes a value of type E as its parameter and returns a boolean value. This
* function is used to determine whether a particular value in the linked list satisfies a certain condition.
* @returns The method `find` returns the first element in the linked list that satisfies the condition specified by
* the callback function. If no element satisfies the condition, it returns `null`.
* the callback function. If no element satisfies the condition, it returns `undefined`.
*/
find(callback: (value: E) => boolean): E | null {
find(callback: (value: E) => boolean): E | undefined {
let current = this.head;
while (current) {
if (callback(current.value)) {
@ -600,7 +600,7 @@ export class DoublyLinkedList<E = any> {
}
current = current.next;
}
return null;
return undefined;
}
/**
@ -641,13 +641,13 @@ export class DoublyLinkedList<E = any> {
* Space Complexity: O(1)
*
* The `findBackward` function iterates through a linked list from the last node to the first node and returns the last
* value that satisfies the given callback function, or null if no value satisfies the callback.
* value that satisfies the given callback function, or undefined if no value satisfies the callback.
* @param callback - A function that takes a value of type E as its parameter and returns a boolean value. This
* function is used to determine whether a given value satisfies a certain condition.
* @returns The method `findBackward` returns the last value in the linked list that satisfies the condition specified by
* the callback function. If no value satisfies the condition, it returns `null`.
* the callback function. If no value satisfies the condition, it returns `undefined`.
*/
findBackward(callback: (value: E) => boolean): E | null {
findBackward(callback: (value: E) => boolean): E | undefined {
let current = this.tail;
while (current) {
if (callback(current.value)) {
@ -655,7 +655,7 @@ export class DoublyLinkedList<E = any> {
}
current = current.prev;
}
return null;
return undefined;
}
/**

View file

@ -7,16 +7,16 @@
*/
export class SinglyLinkedListNode<E = any> {
value: E;
next: SinglyLinkedListNode<E> | null;
next: SinglyLinkedListNode<E> | undefined;
/**
* The constructor function initializes an instance of a class with a given value and sets the next property to null.
* The constructor function initializes an instance of a class with a given value and sets the next property to undefined.
* @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;
this.next = undefined;
}
}
@ -25,8 +25,8 @@ export class SinglyLinkedList<E = any> {
* The constructor initializes the linked list with an empty head, tail, and length.
*/
constructor(elements?: Iterable<E>) {
this._head = null;
this._tail = null;
this._head = undefined;
this._tail = undefined;
this._length = 0;
if (elements) {
for (const el of elements)
@ -34,15 +34,15 @@ export class SinglyLinkedList<E = any> {
}
}
protected _head: SinglyLinkedListNode<E> | null;
protected _head: SinglyLinkedListNode<E> | undefined;
get head(): SinglyLinkedListNode<E> | null {
get head(): SinglyLinkedListNode<E> | undefined {
return this._head;
}
protected _tail: SinglyLinkedListNode<E> | null;
protected _tail: SinglyLinkedListNode<E> | undefined;
get tail(): SinglyLinkedListNode<E> | null {
get tail(): SinglyLinkedListNode<E> | undefined {
return this._tail;
}
@ -128,14 +128,14 @@ export class SinglyLinkedList<E = any> {
* The `pop()` function removes and returns the value of the last element in a linked list, updating the head and tail
* pointers accordingly.
* @returns The method `pop()` returns the value of the node that is being removed from the end of the linked list. If
* the linked list is empty, it returns `null`.
* the linked list is empty, it returns `undefined`.
*/
pop(): E | undefined {
if (!this.head) return undefined;
if (this.head === this.tail) {
const value = this.head.value;
this._head = null;
this._tail = null;
this._head = undefined;
this._tail = undefined;
this._length--;
return value;
}
@ -145,7 +145,7 @@ export class SinglyLinkedList<E = any> {
current = current.next!;
}
const value = this.tail!.value;
current.next = null;
current.next = undefined;
this._tail = current;
this._length--;
return value;
@ -163,7 +163,7 @@ export class SinglyLinkedList<E = any> {
* The `popLast()` function removes and returns the value of the last element in a linked list, updating the head and tail
* pointers accordingly.
* @returns The method `pop()` returns the value of the node that is being removed from the end of the linked list. If
* the linked list is empty, it returns `null`.
* the linked list is empty, it returns `undefined`.
*/
popLast(): E | undefined {
return this.pop();
@ -256,11 +256,11 @@ export class SinglyLinkedList<E = any> {
* Time Complexity: O(n) - Linear time, where n is the index, as it may need to traverse the list to find the desired node.
* Space Complexity: O(1) - Constant space.
*
* The function `getAt` returns the value at a specified index in a linked list, or null if the index is out of range.
* The function `getAt` returns the value at a specified index in a linked list, or undefined if the index is out of range.
* @param {number} index - The index parameter is a number that represents the position of the element we want to
* retrieve from the list.
* @returns The method `getAt(index: number): E | null` returns the value at the specified index in the linked list, or
* `null` if the index is out of bounds.
* @returns The method `getAt(index: number): E | undefined` returns the value at the specified index in the linked list, or
* `undefined` if the index is out of bounds.
*/
getAt(index: number): E | undefined {
if (index < 0 || index >= this.length) return undefined;
@ -284,9 +284,9 @@ export class SinglyLinkedList<E = any> {
* @param {number} index - The `index` parameter is a number that represents the position of the node we want to
* retrieve from the linked list. It indicates the zero-based index of the node we want to access.
* @returns The method `getNodeAt(index: number)` returns a `SinglyLinkedListNode<E>` object if the node at the
* specified index exists, or `null` if the index is out of bounds.
* specified index exists, or `undefined` if the index is out of bounds.
*/
getNodeAt(index: number): SinglyLinkedListNode<E> | null {
getNodeAt(index: number): SinglyLinkedListNode<E> | undefined {
let current = this.head;
for (let i = 0; i < index; i++) {
current = current!.next;
@ -306,7 +306,7 @@ export class SinglyLinkedList<E = any> {
* The `deleteAt` function removes an element at a specified index from a linked list and returns the removed element.
* @param {number} index - The index parameter represents the position of the element that needs to be deleted in the
* data structure. It is of type number.
* @returns The method `deleteAt` returns the value of the node that was deleted, or `null` if the index is out of
* @returns The method `deleteAt` returns the value of the node that was deleted, or `undefined` if the index is out of
* bounds.
*/
deleteAt(index: number): E | undefined {
@ -336,7 +336,7 @@ export class SinglyLinkedList<E = any> {
* @returns The `delete` method returns a boolean value. It returns `true` if the value or node is found and
* successfully deleted from the linked list, and `false` if the value or node is not found in the linked list.
*/
delete(valueOrNode: E | SinglyLinkedListNode<E> | null | undefined): boolean {
delete(valueOrNode: E | SinglyLinkedListNode<E> | undefined | undefined): boolean {
if (!valueOrNode) return false;
let value: E;
if (valueOrNode instanceof SinglyLinkedListNode) {
@ -345,14 +345,14 @@ export class SinglyLinkedList<E = any> {
value = valueOrNode;
}
let current = this.head,
prev = null;
prev = undefined;
while (current) {
if (current.value === value) {
if (prev === null) {
if (prev === undefined) {
this._head = current.next;
if (current === this.tail) {
this._tail = null;
this._tail = undefined;
}
} else {
prev.next = current.next;
@ -416,11 +416,11 @@ export class SinglyLinkedList<E = any> {
}
/**
* The `clear` function resets the linked list by setting the head, tail, and length to null and 0 respectively.
* The `clear` function resets the linked list by setting the head, tail, and length to undefined and 0 respectively.
*/
clear(): void {
this._head = null;
this._tail = null;
this._head = undefined;
this._tail = undefined;
this._length = 0;
}
@ -461,9 +461,9 @@ export class SinglyLinkedList<E = any> {
reverse(): void {
if (!this.head || this.head === this.tail) return;
let prev: SinglyLinkedListNode<E> | null = null;
let current: SinglyLinkedListNode<E> | null = this.head;
let next: SinglyLinkedListNode<E> | null = null;
let prev: SinglyLinkedListNode<E> | undefined = undefined;
let current: SinglyLinkedListNode<E> | undefined = this.head;
let next: SinglyLinkedListNode<E> | undefined = undefined;
while (current) {
next = current.next;
@ -488,9 +488,9 @@ export class SinglyLinkedList<E = any> {
* @param callback - A function that takes a value of type E as its parameter and returns a boolean value. This
* function is used to determine whether a particular value in the linked list satisfies a certain condition.
* @returns The method `find` returns the first element in the linked list that satisfies the condition specified by
* the callback function. If no element satisfies the condition, it returns `null`.
* the callback function. If no element satisfies the condition, it returns `undefined`.
*/
find(callback: (value: E) => boolean): E | null {
find(callback: (value: E) => boolean): E | undefined {
let current = this.head;
while (current) {
if (callback(current.value)) {
@ -498,7 +498,7 @@ export class SinglyLinkedList<E = any> {
}
current = current.next;
}
return null;
return undefined;
}
/**
@ -540,12 +540,12 @@ export class SinglyLinkedList<E = any> {
* Space Complexity: O(1) - Constant space.
*
* The function finds a node in a singly linked list by its value and returns the node if found, otherwise returns
* null.
* undefined.
* @param {E} value - The value parameter is the value that we want to search for in the linked list.
* @returns a `SinglyLinkedListNode<E>` if a node with the specified value is found in the linked list. If no node with
* the specified value is found, the function returns `null`.
* the specified value is found, the function returns `undefined`.
*/
getNode(value: E): SinglyLinkedListNode<E> | null {
getNode(value: E): SinglyLinkedListNode<E> | undefined {
let current = this.head;
while (current) {
@ -555,7 +555,7 @@ export class SinglyLinkedList<E = any> {
current = current.next;
}
return null;
return undefined;
}
/**
@ -620,7 +620,7 @@ export class SinglyLinkedList<E = any> {
* existing value or node, and false if the existing value or node was not found in the linked list.
*/
insertAfter(existingValueOrNode: E | SinglyLinkedListNode<E>, newValue: E): boolean {
let existingNode: E | SinglyLinkedListNode<E> | null;
let existingNode: E | SinglyLinkedListNode<E> | undefined;
if (existingValueOrNode instanceof SinglyLinkedListNode) {
existingNode = existingValueOrNode;

View file

@ -27,7 +27,7 @@ export class SkipList<K, V> {
* level in the skip list. It is used to determine the height of each node in the skip list.
*/
constructor(maxLevel = 16, probability = 0.5) {
this._head = new SkipListNode<K, V>(null as any, null as any, maxLevel);
this._head = new SkipListNode<K, V>(undefined as any, undefined as any, maxLevel);
this._level = 0;
this._maxLevel = maxLevel;
this._probability = probability;
@ -88,7 +88,7 @@ export class SkipList<K, V> {
update[i].forward[i] = newNode;
}
if (newNode.forward[0] !== null) {
if (!newNode.forward[0]) {
this._level = Math.max(this.level, newNode.forward.length);
}
}
@ -172,7 +172,7 @@ export class SkipList<K, V> {
}
update[i].forward[i] = current.forward[i];
}
while (this.level > 0 && this.head.forward[this.level - 1] === null) {
while (this.level > 0 && !this.head.forward[this.level - 1]) {
this._level--;
}
return true;
@ -259,7 +259,7 @@ export class SkipList<K, V> {
*/
lower(key: K): V | undefined {
let current = this.head;
let lastLess = null;
let lastLess = undefined;
for (let i = this.level - 1; i >= 0; i--) {
while (current.forward[i] && current.forward[i].key < key) {

View file

@ -17,8 +17,8 @@ describe('DoublyLinkedList Operation Test', () => {
});
it('should out of bound index', () => {
expect(list.getNodeAt(-1)).toBe(null);
expect(list.getNodeAt(5)).toBe(null);
expect(list.getNodeAt(-1)).toBe(undefined);
expect(list.getNodeAt(5)).toBe(undefined);
expect(list.insertAt(5, 6)).toBe(true);
});
@ -37,16 +37,16 @@ describe('DoublyLinkedList Operation Test', () => {
expect(list.tail?.value).toBe(4);
});
it('should find null', () => {
expect(list.find(value => value === 6)).toBe(null);
it('should find undefined', () => {
expect(list.find(value => value === 6)).toBe(undefined);
});
it('should indexOf -1', () => {
expect(list.indexOf(6)).toBe(-1);
});
it('should findBackward null', () => {
expect(list.findBackward(value => value === 0)).toBe(null);
it('should findBackward undefined', () => {
expect(list.findBackward(value => value === 0)).toBe(undefined);
});
it('should insertAfter tail', () => {
@ -69,8 +69,8 @@ describe('DoublyLinkedList Operation Test', () => {
it('should initialize an empty list', () => {
expect(list.length).toBe(0);
expect(list.head).toBeNull();
expect(list.tail).toBeNull();
expect(list.head).toBe(undefined);
expect(list.tail).toBe(undefined);
});
it('should push elements to the list', () => {
@ -134,8 +134,8 @@ describe('DoublyLinkedList Operation Test', () => {
// Deleting from the end
list.deleteAt(0);
expect(list.length).toBe(0);
expect(list.head).toBeNull();
expect(list.tail).toBeNull();
expect(list.head).toBe(undefined);
expect(list.tail).toBe(undefined);
});
it('should delete elements by value', () => {
@ -154,8 +154,8 @@ describe('DoublyLinkedList Operation Test', () => {
list.delete(3);
expect(list.length).toBe(0);
expect(list.head).toBeNull();
expect(list.tail).toBeNull();
expect(list.head).toBe(undefined);
expect(list.tail).toBe(undefined);
});
it('should reverse the linked list', () => {
@ -259,8 +259,8 @@ describe('DoublyLinkedList Operation Test', () => {
list.clear();
expect(list.length).toBe(0);
expect(list.head).toBe(null);
expect(list.tail).toBe(null);
expect(list.head).toBe(undefined);
expect(list.tail).toBe(undefined);
});
it('should create a reversed array of values', () => {

View file

@ -333,7 +333,7 @@ describe('SinglyLinkedList Operation Test', () => {
list.push(1);
list.push(3);
const result = list.find(data => data % 2 === 0);
expect(result).toBeNull();
expect(result).toBe(undefined);
});
});
@ -402,8 +402,8 @@ describe('SinglyLinkedList', () => {
});
it('should initialize an empty list', () => {
expect(list.head).toBeNull();
expect(list.tail).toBeNull();
expect(list.head).toBe(undefined);
expect(list.tail).toBe(undefined);
expect(list.length).toBe(0);
});

View file

@ -81,6 +81,6 @@ describe('SkipList', () => {
it('lower(key) should return the getLast element less than the given key', () => {
expect(skipList.lower(2)).toBe('One');
expect(skipList.lower(1)).toBe(null);
expect(skipList.lower(1)).toBe(undefined);
});
});