directed-graph-typed
Version:
281 lines (247 loc) • 8.48 kB
text/typescript
/**
* data-structure-typed
*
* @author Pablo Zeng
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type { SkipLinkedListOptions } from '../../types';
export class SkipListNode<K, V> {
key: K;
value: V;
forward: SkipListNode<K, V>[];
constructor(key: K, value: V, level: number) {
this.key = key;
this.value = value;
this.forward = new Array(level);
}
}
/**
*
*/
export class SkipList<K, V> {
/**
* The constructor function initializes a SkipLinkedList object with optional options and elements.
* @param elements - The `elements` parameter is an iterable containing key-value pairs `[K, V]`. It
* is used to initialize the SkipLinkedList with the given key-value pairs. If no elements are
* provided, the SkipLinkedList will be empty.
* @param {SkipLinkedListOptions} [options] - The `options` parameter is an optional object that can
* contain two properties:
*/
constructor(elements: Iterable<[K, V]> = [], options?: SkipLinkedListOptions) {
if (options) {
const { maxLevel, probability } = options;
if (typeof maxLevel === 'number') this._maxLevel = maxLevel;
if (typeof probability === 'number') this._probability = probability;
}
if (elements) {
for (const [key, value] of elements) this.add(key, value);
}
}
protected _head: SkipListNode<K, V> = new SkipListNode<K, V>(undefined as any, undefined as any, this.maxLevel);
/**
* The function returns the head node of a SkipList.
* @returns The method is returning a SkipListNode object with generic key type K and value type V.
*/
get head(): SkipListNode<K, V> {
return this._head;
}
protected _level: number = 0;
/**
* The function returns the value of the protected variable _level.
* @returns The level property of the object.
*/
get level(): number {
return this._level;
}
protected _maxLevel: number = 16;
/**
* The function returns the maximum level.
* @returns The value of the variable `_maxLevel` is being returned.
*/
get maxLevel(): number {
return this._maxLevel;
}
protected _probability: number = 0.5;
/**
* The function returns the probability value.
* @returns The probability value stored in the protected variable `_probability` is being returned.
*/
get probability(): number {
return this._probability;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* 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.
*/
get first(): V | undefined {
const firstNode = this.head.forward[0];
return firstNode ? firstNode.value : undefined;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* 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.
*/
get last(): 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;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* 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.
* @param {V} value - The "value" parameter represents the value associated with the key that is being added to the Skip
* List.
*/
add(key: K, value: V): void {
const newNode = new SkipListNode(key, value, this._randomLevel());
const update: SkipListNode<K, V>[] = new Array(this.maxLevel).fill(this.head);
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];
}
update[i] = current;
}
for (let i = 0; i < newNode.forward.length; i++) {
newNode.forward[i] = update[i].forward[i];
update[i].forward[i] = newNode;
}
if (!newNode.forward[0]) {
this._level = Math.max(this.level, newNode.forward.length);
}
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The function `get` retrieves the value associated with a given key from a skip list data structure.
* @param {K} key - The `key` parameter is the key of the element that we want to retrieve from the data structure.
* @returns The method `get(key: K)` returns the value associated with the given key if it exists in the data structure,
* otherwise it returns `undefined`.
*/
get(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];
}
}
current = current.forward[0];
if (current && current.key === key) {
return current.value;
}
return undefined;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The function checks if a key exists in a data structure.
* @param {K} key - The parameter "key" is of type K, which represents the type of the key being
* checked.
* @returns a boolean value.
*/
has(key: K): boolean {
return this.get(key) !== undefined;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* 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.
* @returns The `delete` method returns a boolean value. It returns `true` if the key was successfully removed from the
* skip list, and `false` if the key was not found in the skip list.
*/
delete(key: K): boolean {
const update: SkipListNode<K, V>[] = new Array(this.maxLevel).fill(this.head);
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];
}
update[i] = current;
}
current = current.forward[0];
if (current && current.key === key) {
for (let i = 0; i < this.level; i++) {
if (update[i].forward[i] !== current) {
break;
}
update[i].forward[i] = current.forward[i];
}
while (this.level > 0 && !this.head.forward[this.level - 1]) {
this._level--;
}
return true;
}
return false;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* 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;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* 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 = undefined;
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;
}
/**
* Time Complexity: O(maxLevel)
* Space Complexity: O(1)
*
* The function "_randomLevel" generates a random level based on a given probability and maximum level.
* @returns the level, which is a number.
*/
protected _randomLevel(): number {
let level = 1;
while (Math.random() < this.probability && level < this.maxLevel) {
level++;
}
return level;
}
}