deque-typed
Version:
425 lines (424 loc) • 15.4 kB
TypeScript
/**
* data-structure-typed
*
* @author Pablo Zeng
* @copyright Copyright (c) 2022 Pablo Zeng
* @license MIT License
*/
import type { Comparator, TreeMultiMapOptions } from '../../types';
import { Range } from '../../common';
import { RedBlackTreeNode } from './red-black-tree';
/**
* Node type used by TreeMultiMap (alias to RedBlackTreeNode for backward compatibility).
*
* @deprecated Direct node manipulation is discouraged. Use TreeMultiMap methods instead.
*/
export declare class TreeMultiMapNode<K = any, V = any> extends RedBlackTreeNode<K, V[]> {
constructor(key: K, value?: V[]);
}
/**
* TreeMultiMap (ordered MultiMap) — key → bucket (Array of values).
*
* Semantics (RFC):
* - Bucketed design: each key appears once; duplicates live in the bucket.
* - `get(key)` returns a **live** bucket reference.
* - Default iteration yields bucket entries: `[K, V[]]`.
* - Navigable operations (`first/last/ceiling/...`) return entry tuples like TreeMap.
* @example
* // players ranked by score with their equipment
* type Equipment = {
* name: string; // Equipment name
* quality: 'legendary' | 'epic' | 'rare' | 'common';
* level: number;
* };
*
* type Player = {
* name: string;
* score: number;
* equipments: Equipment[];
* };
*
* // Mock player data with their scores and equipment
* const players: Player[] = [
* {
* name: 'DragonSlayer',
* score: 8750,
* equipments: [
* { name: 'AWM', quality: 'legendary', level: 85 },
* { name: 'Level 3 Helmet', quality: 'epic', level: 80 },
* { name: 'Extended Quickdraw Mag', quality: 'rare', level: 75 },
* { name: 'Compensator', quality: 'epic', level: 78 },
* { name: 'Vertical Grip', quality: 'rare', level: 72 }
* ]
* },
* {
* name: 'ShadowNinja',
* score: 7200,
* equipments: [
* { name: 'M416', quality: 'epic', level: 75 },
* { name: 'Ghillie Suit', quality: 'rare', level: 70 },
* { name: 'Red Dot Sight', quality: 'common', level: 65 },
* { name: 'Extended QuickDraw Mag', quality: 'rare', level: 68 }
* ]
* },
* {
* name: 'RuneMaster',
* score: 9100,
* equipments: [
* { name: 'KAR98K', quality: 'legendary', level: 90 },
* { name: 'Level 3 Vest', quality: 'legendary', level: 85 },
* { name: 'Holographic Sight', quality: 'epic', level: 82 },
* { name: 'Suppressor', quality: 'legendary', level: 88 },
* { name: 'Level 3 Backpack', quality: 'epic', level: 80 }
* ]
* },
* {
* name: 'BattleKing',
* score: 8500,
* equipments: [
* { name: 'AUG', quality: 'epic', level: 82 },
* { name: 'Red Dot Sight', quality: 'rare', level: 75 },
* { name: 'Extended Mag', quality: 'common', level: 70 },
* { name: 'Tactical Stock', quality: 'rare', level: 76 }
* ]
* },
* {
* name: 'SniperElite',
* score: 7800,
* equipments: [
* { name: 'M24', quality: 'legendary', level: 88 },
* { name: 'Compensator', quality: 'epic', level: 80 },
* { name: 'Scope 8x', quality: 'legendary', level: 85 },
* { name: 'Level 2 Helmet', quality: 'rare', level: 75 }
* ]
* },
* {
* name: 'RushMaster',
* score: 7500,
* equipments: [
* { name: 'Vector', quality: 'rare', level: 72 },
* { name: 'Level 2 Helmet', quality: 'common', level: 65 },
* { name: 'Quickdraw Mag', quality: 'common', level: 60 },
* { name: 'Laser Sight', quality: 'rare', level: 68 }
* ]
* },
* {
* name: 'GhostWarrior',
* score: 8200,
* equipments: [
* { name: 'SCAR-L', quality: 'epic', level: 78 },
* { name: 'Extended Quickdraw Mag', quality: 'rare', level: 70 },
* { name: 'Holographic Sight', quality: 'epic', level: 75 },
* { name: 'Suppressor', quality: 'rare', level: 72 },
* { name: 'Vertical Grip', quality: 'common', level: 65 }
* ]
* },
* {
* name: 'DeathDealer',
* score: 7300,
* equipments: [
* { name: 'SKS', quality: 'epic', level: 76 },
* { name: 'Holographic Sight', quality: 'rare', level: 68 },
* { name: 'Extended Mag', quality: 'common', level: 65 }
* ]
* },
* {
* name: 'StormRider',
* score: 8900,
* equipments: [
* { name: 'MK14', quality: 'legendary', level: 92 },
* { name: 'Level 3 Backpack', quality: 'legendary', level: 85 },
* { name: 'Scope 8x', quality: 'epic', level: 80 },
* { name: 'Suppressor', quality: 'legendary', level: 88 },
* { name: 'Tactical Stock', quality: 'rare', level: 75 }
* ]
* },
* {
* name: 'CombatLegend',
* score: 7600,
* equipments: [
* { name: 'UMP45', quality: 'rare', level: 74 },
* { name: 'Level 2 Vest', quality: 'common', level: 67 },
* { name: 'Red Dot Sight', quality: 'common', level: 62 },
* { name: 'Extended Mag', quality: 'rare', level: 70 }
* ]
* }
* ];
*
* // Create a TreeMultiMap for player rankings
* const playerRankings = new TreeMultiMap<number, Equipment, Player>(players, {
* toEntryFn: ({ score, equipments }) => [score, equipments],
* isMapMode: false
* });
*
* const topPlayersEquipments = playerRankings.rangeSearch([8900, 10000], node => playerRankings.get(node.key));
* console.log(topPlayersEquipments); // [
* // [
* // {
* // name: 'MK14',
* // quality: 'legendary',
* // level: 92
* // },
* // { name: 'Level 3 Backpack', quality: 'legendary', level: 85 },
* // {
* // name: 'Scope 8x',
* // quality: 'epic',
* // level: 80
* // },
* // { name: 'Suppressor', quality: 'legendary', level: 88 },
* // {
* // name: 'Tactical Stock',
* // quality: 'rare',
* // level: 75
* // }
* // ],
* // [
* // { name: 'KAR98K', quality: 'legendary', level: 90 },
* // {
* // name: 'Level 3 Vest',
* // quality: 'legendary',
* // level: 85
* // },
* // { name: 'Holographic Sight', quality: 'epic', level: 82 },
* // {
* // name: 'Suppressor',
* // quality: 'legendary',
* // level: 88
* // },
* // { name: 'Level 3 Backpack', quality: 'epic', level: 80 }
* // ]
* // ];
*/
export declare class TreeMultiMap<K = any, V = any, R = any> implements Iterable<[K, V[]]> {
#private;
/**
* Creates a new TreeMultiMap.
* @param keysNodesEntriesOrRaws - Initial entries, or raw elements if `toEntryFn` is provided.
* @param options - Configuration options including optional `toEntryFn` to transform raw elements.
* @remarks Time O(m log m), Space O(m) where m is the number of initial entries
* @example
* // Standard usage with entries
* const mmap = new TreeMultiMap([['a', ['x', 'y']], ['b', ['z']]]);
*
* // Using toEntryFn to transform raw objects
* const players = [{ score: 100, items: ['sword'] }, { score: 200, items: ['shield', 'bow'] }];
* const mmap = new TreeMultiMap(players, { toEntryFn: p => [p.score, p.items] });
*/
constructor(keysNodesEntriesOrRaws?: Iterable<K | [K | null | undefined, V[] | undefined] | null | undefined | R>, options?: TreeMultiMapOptions<K, V[], R>);
/**
* Validates the key against the default comparator rules.
* @remarks Time O(1), Space O(1)
*/
private _validateKey;
/**
* Number of distinct keys.
* @remarks Time O(1), Space O(1)
*/
get size(): number;
/**
* Whether the map is empty.
* @remarks Time O(1), Space O(1)
*/
isEmpty(): boolean;
/**
* Removes all entries from the map.
* @remarks Time O(1), Space O(1)
*/
clear(): void;
/**
* Bucket length for a key (missing => 0).
* @remarks Time O(log n), Space O(1)
*/
count(key: K): number;
/**
* Total number of values across all buckets (Σ bucket.length).
* @remarks Time O(n), Space O(1)
*/
get totalSize(): number;
/**
* Whether the map contains the given key.
* @remarks Time O(log n), Space O(1)
*/
has(key: K): boolean;
/**
* Live bucket reference (do not auto-delete key if bucket becomes empty via mutation).
* @remarks Time O(log n), Space O(1)
*/
get(key: K): V[] | undefined;
/**
* Append a single value.
* @remarks Time O(log n), Space O(1)
*/
add(key: K, value: V): boolean;
/**
* Alias for compatibility with existing TreeMultiMap semantics.
* @remarks Time O(log n), Space O(1) for single value; O(log n + m) for bucket append
*/
set(entry: [K | null | undefined, V[] | undefined] | K | null | undefined, value?: V): boolean;
set(key: K, value: V): boolean;
/**
* Deletes a key and its entire bucket.
* @remarks Time O(log n), Space O(1)
*/
delete(key: K): boolean;
/**
* Check if a specific value exists in a key's bucket.
* @remarks Time O(log n + m), Space O(1) where m is bucket size
*/
hasEntry(key: K, value: V, eq?: (a: V, b: V) => boolean): boolean;
/**
* Delete a single occurrence of a value from a key's bucket.
* @remarks Time O(log n + m), Space O(1) where m is bucket size
*/
deleteValue(key: K, value: V, eq?: (a: V, b: V) => boolean): boolean;
/**
* Delete all occurrences of a value from a key's bucket.
* @remarks Time O(log n + m), Space O(1) where m is bucket size
*/
deleteValues(key: K, value: V, eq?: (a: V, b: V) => boolean): number;
/**
* Iterates over all entries as [key, bucket] pairs.
* @remarks Time O(n), Space O(1)
*/
[Symbol.iterator](): Iterator<[K, V[]]>;
/**
* Iterates over all keys.
* @remarks Time O(n), Space O(1)
*/
keys(): IterableIterator<K>;
/**
* Iterates over all buckets.
* @remarks Time O(n), Space O(1)
*/
values(): IterableIterator<V[]>;
/**
* Iterates over all entries for a specific key.
* @remarks Time O(log n + m), Space O(1) where m is bucket size
*/
entriesOf(key: K): IterableIterator<[K, V]>;
/**
* Iterates over all values for a specific key.
* @remarks Time O(log n + m), Space O(1) where m is bucket size
*/
valuesOf(key: K): IterableIterator<V>;
/**
* Iterates over all [key, value] pairs (flattened from buckets).
* @remarks Time O(T), Space O(1) where T is totalSize
*/
flatEntries(): IterableIterator<[K, V]>;
/**
* Returns the entry with the smallest key.
* @remarks Time O(log n), Space O(1)
* @example
* const map = new TreeMultiMap([[1, ['a']], [2, ['b']]]);
* map.first(); // [1, ['a']]
*/
first(): [K, V[]] | undefined;
/**
* Returns the entry with the largest key.
* @remarks Time O(log n), Space O(1)
* @example
* const map = new TreeMultiMap([[1, ['a']], [2, ['b']]]);
* map.last(); // [2, ['b']]
*/
last(): [K, V[]] | undefined;
/**
* Removes and returns the entry with the smallest key.
* @remarks Time O(log n), Space O(1)
* @example
* const map = new TreeMultiMap([[1, ['a']], [2, ['b']]]);
* map.pollFirst(); // [1, ['a']]
* map.has(1); // false
*/
pollFirst(): [K, V[]] | undefined;
/**
* Removes and returns the entry with the largest key.
* @remarks Time O(log n), Space O(1)
* @example
* const map = new TreeMultiMap([[1, ['a']], [2, ['b']]]);
* map.pollLast(); // [2, ['b']]
* map.has(2); // false
*/
pollLast(): [K, V[]] | undefined;
/**
* Returns the entry with the smallest key >= given key.
* @remarks Time O(log n), Space O(1)
* @example
* const map = new TreeMultiMap([[10, ['a']], [20, ['b']], [30, ['c']]]);
* map.ceiling(15); // [20, ['b']]
* map.ceiling(20); // [20, ['b']]
*/
ceiling(key: K): [K, V[]] | undefined;
/**
* Returns the entry with the largest key <= given key.
* @remarks Time O(log n), Space O(1)
* @example
* const map = new TreeMultiMap([[10, ['a']], [20, ['b']], [30, ['c']]]);
* map.floor(25); // [20, ['b']]
* map.floor(20); // [20, ['b']]
*/
floor(key: K): [K, V[]] | undefined;
/**
* Returns the entry with the smallest key > given key.
* @remarks Time O(log n), Space O(1)
* @example
* const map = new TreeMultiMap([[10, ['a']], [20, ['b']], [30, ['c']]]);
* map.higher(10); // [20, ['b']]
* map.higher(15); // [20, ['b']]
*/
higher(key: K): [K, V[]] | undefined;
/**
* Returns the entry with the largest key < given key.
* @remarks Time O(log n), Space O(1)
* @example
* const map = new TreeMultiMap([[10, ['a']], [20, ['b']], [30, ['c']]]);
* map.lower(20); // [10, ['a']]
* map.lower(15); // [10, ['a']]
*/
lower(key: K): [K, V[]] | undefined;
/**
* Prints the internal tree structure (for debugging).
* @remarks Time O(n), Space O(n)
*/
print(): void;
/**
* Executes a callback for each entry.
* @remarks Time O(n), Space O(1)
*/
forEach(callback: (value: V[], key: K, map: this) => void): void;
/**
* Creates a new map with entries that pass the predicate.
* @remarks Time O(n), Space O(n)
*/
filter(predicate: (value: V[], key: K, map: this) => boolean): TreeMultiMap<K, V, R>;
/**
* Creates a new map by transforming each entry.
* @remarks Time O(n log n), Space O(n)
*/
map<V2>(mapper: (value: V[], key: K, map: this) => [K, V2[]]): TreeMultiMap<K, V2, R>;
/**
* Reduces all entries to a single value.
* @remarks Time O(n), Space O(1)
*/
reduce<U>(callback: (accumulator: U, value: V[], key: K, map: this) => U, initialValue: U): U;
/**
* Sets multiple entries at once.
* @remarks Time O(m log n), Space O(m) where m is input size
*/
setMany(keysNodesEntriesOrRaws: Iterable<K | [K | null | undefined, V[] | undefined]>): boolean[];
/**
* Searches for entries within a key range.
* @remarks Time O(log n + k), Space O(k) where k is result size
*/
rangeSearch<C extends (node: RedBlackTreeNode<K, V[]>) => unknown>(range: Range<K> | [K, K], callback?: C): ReturnType<C>[];
/**
* Creates a shallow clone of this map.
* @remarks Time O(n log n), Space O(n)
*/
clone(): TreeMultiMap<K, V, R>;
/**
* Expose comparator for advanced usage/testing (read-only).
* @remarks Time O(1), Space O(1)
*/
get comparator(): Comparator<K>;
}