data-structure-typed 2.5.2 → 2.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -1
- package/MIGRATION.md +169 -0
- package/README.md +60 -6
- package/README_CN.md +551 -143
- package/SPECIFICATION.md +20 -14
- package/SPECIFICATION.zh-CN.md +20 -14
- package/dist/cjs/binary-tree.cjs +2417 -132
- package/dist/cjs/graph.cjs +248 -14
- package/dist/cjs/hash.cjs +62 -7
- package/dist/cjs/heap.cjs +103 -16
- package/dist/cjs/index.cjs +3046 -124
- package/dist/cjs/linked-list.cjs +219 -0
- package/dist/cjs/matrix.cjs +32 -0
- package/dist/cjs/priority-queue.cjs +101 -14
- package/dist/cjs/queue.cjs +215 -0
- package/dist/cjs/stack.cjs +44 -4
- package/dist/cjs/trie.cjs +44 -0
- package/dist/cjs-legacy/binary-tree.cjs +2406 -123
- package/dist/cjs-legacy/graph.cjs +248 -14
- package/dist/cjs-legacy/hash.cjs +62 -7
- package/dist/cjs-legacy/heap.cjs +103 -16
- package/dist/cjs-legacy/index.cjs +3105 -185
- package/dist/cjs-legacy/linked-list.cjs +219 -0
- package/dist/cjs-legacy/matrix.cjs +32 -0
- package/dist/cjs-legacy/priority-queue.cjs +101 -14
- package/dist/cjs-legacy/queue.cjs +215 -0
- package/dist/cjs-legacy/stack.cjs +44 -4
- package/dist/cjs-legacy/trie.cjs +44 -0
- package/dist/esm/binary-tree.mjs +2417 -132
- package/dist/esm/graph.mjs +248 -14
- package/dist/esm/hash.mjs +62 -7
- package/dist/esm/heap.mjs +103 -16
- package/dist/esm/index.mjs +3046 -124
- package/dist/esm/linked-list.mjs +219 -0
- package/dist/esm/matrix.mjs +32 -0
- package/dist/esm/priority-queue.mjs +101 -14
- package/dist/esm/queue.mjs +215 -0
- package/dist/esm/stack.mjs +44 -4
- package/dist/esm/trie.mjs +44 -0
- package/dist/esm-legacy/binary-tree.mjs +2406 -123
- package/dist/esm-legacy/graph.mjs +248 -14
- package/dist/esm-legacy/hash.mjs +62 -7
- package/dist/esm-legacy/heap.mjs +103 -16
- package/dist/esm-legacy/index.mjs +3105 -185
- package/dist/esm-legacy/linked-list.mjs +219 -0
- package/dist/esm-legacy/matrix.mjs +32 -0
- package/dist/esm-legacy/priority-queue.mjs +101 -14
- package/dist/esm-legacy/queue.mjs +215 -0
- package/dist/esm-legacy/stack.mjs +44 -4
- package/dist/esm-legacy/trie.mjs +44 -0
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +50 -2
- package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +56 -0
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +116 -15
- package/dist/types/data-structures/binary-tree/bst.d.ts +99 -3
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +79 -8
- package/dist/types/data-structures/binary-tree/segment-tree.d.ts +24 -0
- package/dist/types/data-structures/binary-tree/tree-map.d.ts +520 -1
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +489 -1
- package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +393 -1
- package/dist/types/data-structures/binary-tree/tree-set.d.ts +500 -1
- package/dist/types/data-structures/graph/directed-graph.d.ts +40 -0
- package/dist/types/data-structures/graph/undirected-graph.d.ts +36 -0
- package/dist/types/data-structures/hash/hash-map.d.ts +51 -6
- package/dist/types/data-structures/heap/heap.d.ts +98 -12
- package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +75 -0
- package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +61 -1
- package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +72 -0
- package/dist/types/data-structures/matrix/matrix.d.ts +32 -0
- package/dist/types/data-structures/queue/deque.d.ts +82 -0
- package/dist/types/data-structures/queue/queue.d.ts +61 -0
- package/dist/types/data-structures/stack/stack.d.ts +42 -2
- package/dist/types/data-structures/trie/trie.d.ts +48 -0
- package/dist/types/interfaces/binary-tree.d.ts +2 -3
- package/dist/umd/data-structure-typed.js +3105 -185
- package/dist/umd/data-structure-typed.min.js +4 -4
- package/docs-site-docusaurus/docs/api/classes/AVLTree.md +188 -200
- package/docs-site-docusaurus/docs/api/classes/AVLTreeNode.md +11 -11
- package/docs-site-docusaurus/docs/api/classes/AbstractGraph.md +62 -62
- package/docs-site-docusaurus/docs/api/classes/BST.md +183 -195
- package/docs-site-docusaurus/docs/api/classes/BSTNode.md +13 -13
- package/docs-site-docusaurus/docs/api/classes/BinaryIndexedTree.md +15 -15
- package/docs-site-docusaurus/docs/api/classes/BinaryTree.md +143 -155
- package/docs-site-docusaurus/docs/api/classes/BinaryTreeNode.md +13 -13
- package/docs-site-docusaurus/docs/api/classes/Deque.md +99 -85
- package/docs-site-docusaurus/docs/api/classes/DirectedGraph.md +73 -73
- package/docs-site-docusaurus/docs/api/classes/DoublyLinkedList.md +100 -70
- package/docs-site-docusaurus/docs/api/classes/DoublyLinkedListNode.md +8 -8
- package/docs-site-docusaurus/docs/api/classes/FibonacciHeap.md +12 -12
- package/docs-site-docusaurus/docs/api/classes/FibonacciHeapNode.md +1 -1
- package/docs-site-docusaurus/docs/api/classes/HashMap.md +38 -38
- package/docs-site-docusaurus/docs/api/classes/Heap.md +96 -85
- package/docs-site-docusaurus/docs/api/classes/IterableElementBase.md +25 -25
- package/docs-site-docusaurus/docs/api/classes/IterableEntryBase.md +23 -23
- package/docs-site-docusaurus/docs/api/classes/LinearBase.md +48 -48
- package/docs-site-docusaurus/docs/api/classes/LinearLinkedBase.md +52 -52
- package/docs-site-docusaurus/docs/api/classes/LinkedHashMap.md +42 -42
- package/docs-site-docusaurus/docs/api/classes/LinkedListNode.md +6 -6
- package/docs-site-docusaurus/docs/api/classes/LinkedListQueue.md +74 -74
- package/docs-site-docusaurus/docs/api/classes/MapGraph.md +73 -73
- package/docs-site-docusaurus/docs/api/classes/Matrix.md +31 -31
- package/docs-site-docusaurus/docs/api/classes/MaxHeap.md +104 -89
- package/docs-site-docusaurus/docs/api/classes/MaxPriorityQueue.md +104 -89
- package/docs-site-docusaurus/docs/api/classes/MinHeap.md +104 -89
- package/docs-site-docusaurus/docs/api/classes/MinPriorityQueue.md +104 -89
- package/docs-site-docusaurus/docs/api/classes/Navigator.md +5 -5
- package/docs-site-docusaurus/docs/api/classes/PriorityQueue.md +103 -88
- package/docs-site-docusaurus/docs/api/classes/Queue.md +111 -59
- package/docs-site-docusaurus/docs/api/classes/RedBlackTree.md +200 -212
- package/docs-site-docusaurus/docs/api/classes/SegmentTree.md +10 -10
- package/docs-site-docusaurus/docs/api/classes/SinglyLinkedList.md +75 -75
- package/docs-site-docusaurus/docs/api/classes/SinglyLinkedListNode.md +6 -6
- package/docs-site-docusaurus/docs/api/classes/SkipList.md +37 -37
- package/docs-site-docusaurus/docs/api/classes/Stack.md +42 -42
- package/docs-site-docusaurus/docs/api/classes/TreeMap.md +107 -36
- package/docs-site-docusaurus/docs/api/classes/TreeMultiMap.md +43 -43
- package/docs-site-docusaurus/docs/api/classes/TreeSet.md +106 -35
- package/docs-site-docusaurus/docs/api/classes/Trie.md +43 -43
- package/docs-site-docusaurus/docs/api/classes/TrieNode.md +8 -8
- package/docs-site-docusaurus/docs/api/classes/UndirectedGraph.md +72 -72
- package/docs-site-docusaurus/docs/guide/architecture.md +75 -7
- package/docs-site-docusaurus/docs/guide/concepts.md +53 -34
- package/docs-site-docusaurus/docs/guide/faq.md +53 -0
- package/docs-site-docusaurus/docs/guide/guides.md +8 -9
- package/docs-site-docusaurus/docs/guide/integrations.md +74 -177
- package/docs-site-docusaurus/docs/guide/overview.md +131 -17
- package/docs-site-docusaurus/src/pages/index.tsx +4 -0
- package/docs-site-docusaurus/typedoc.json +1 -0
- package/package.json +7 -6
- package/src/data-structures/binary-tree/avl-tree.ts +52 -5
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +56 -0
- package/src/data-structures/binary-tree/binary-tree.ts +167 -81
- package/src/data-structures/binary-tree/bst.ts +101 -7
- package/src/data-structures/binary-tree/red-black-tree.ts +82 -15
- package/src/data-structures/binary-tree/segment-tree.ts +24 -0
- package/src/data-structures/binary-tree/tree-map.ts +540 -3
- package/src/data-structures/binary-tree/tree-multi-map.ts +490 -2
- package/src/data-structures/binary-tree/tree-multi-set.ts +393 -1
- package/src/data-structures/binary-tree/tree-set.ts +520 -3
- package/src/data-structures/graph/directed-graph.ts +41 -1
- package/src/data-structures/graph/undirected-graph.ts +37 -1
- package/src/data-structures/hash/hash-map.ts +67 -12
- package/src/data-structures/heap/heap.ts +107 -19
- package/src/data-structures/linked-list/doubly-linked-list.ts +88 -0
- package/src/data-structures/linked-list/singly-linked-list.ts +61 -1
- package/src/data-structures/linked-list/skip-linked-list.ts +72 -0
- package/src/data-structures/matrix/matrix.ts +32 -0
- package/src/data-structures/queue/deque.ts +85 -0
- package/src/data-structures/queue/queue.ts +73 -0
- package/src/data-structures/stack/stack.ts +45 -5
- package/src/data-structures/trie/trie.ts +48 -0
- package/src/interfaces/binary-tree.ts +1 -9
- package/.vitepress/cache/deps_temp_51f5f1b0/chunk-7OIKW5WK.js +0 -12984
- package/.vitepress/cache/deps_temp_51f5f1b0/package.json +0 -3
- package/.vitepress/cache/deps_temp_51f5f1b0/vitepress___@vue_devtools-api.js +0 -4505
- package/.vitepress/cache/deps_temp_51f5f1b0/vitepress___@vueuse_core.js +0 -9731
- package/.vitepress/cache/deps_temp_51f5f1b0/vue.js +0 -347
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
sidebar_label: "INTEGRATIONS"
|
|
3
3
|
description: "Integrate data-structure-typed with React, Express, NestJS, and other frameworks. Production-ready patterns."
|
|
4
4
|
title: "Framework Integrations — React, Express, NestJS"
|
|
5
|
-
keywords: [data-structure-typed react, typescript data structures express, nestjs data structures, production patterns]
|
|
5
|
+
keywords: ["data-structure-typed react", "typescript data structures express", "nestjs data structures", "production patterns"]
|
|
6
6
|
---
|
|
7
|
-
|
|
8
7
|
# INTEGRATIONS
|
|
9
8
|
|
|
10
9
|
How to use data-structure-typed with React, Express, Nest.js, and other frameworks.
|
|
11
10
|
|
|
12
|
-
**[Back to README](
|
|
11
|
+
**[Back to README](/docs/guide/quick-start) • [Code Examples](/guide/guides.md) • [Performance](/guide/performance.md)**
|
|
13
12
|
|
|
14
13
|
---
|
|
15
14
|
|
|
@@ -291,6 +290,8 @@ app.get('/api/data', (req, res) => {
|
|
|
291
290
|
|
|
292
291
|
### Use Case: Product Price Index Service
|
|
293
292
|
|
|
293
|
+
> Full working demo: [StackBlitz NestJS Playground](https://stackblitz.com/github/zrwusa/dst-playgrounds/tree/main/apps/nestjs?file=src%2Fproduct%2Fservices%2Fproduct-price-index.service.ts&title=data-structure-typed%20%E2%80%94%20NestJS%20Product%20API)
|
|
294
|
+
|
|
294
295
|
```typescript
|
|
295
296
|
import {
|
|
296
297
|
BadRequestException,
|
|
@@ -309,7 +310,6 @@ export interface Product {
|
|
|
309
310
|
lastUpdated?: Date;
|
|
310
311
|
}
|
|
311
312
|
|
|
312
|
-
/** KEY INSIGHT: Use compound keys to solve the problem of "multiple products at the same price" */
|
|
313
313
|
interface CompositeKey {
|
|
314
314
|
price: number;
|
|
315
315
|
productId: string;
|
|
@@ -328,13 +328,8 @@ export type TierName = 'budget' | 'mid-range' | 'premium';
|
|
|
328
328
|
* Point Lookup | O(1) | O(1) | O(1)
|
|
329
329
|
* Insert/Update | O(log n) | O(n) | O(log n)
|
|
330
330
|
* Sort by Price | O(n) | O(n log n)| O(n log n)
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
* Advantages:
|
|
334
|
-
* - O(1) idToKeyMap lookup + O(log n) tree operations
|
|
335
|
-
* - Automatic ordering without post-sort
|
|
336
|
-
* - Efficient range queries for pricing tiers
|
|
337
|
-
* - Low memory footprint vs duplicate maps
|
|
331
|
+
* Pagination | O(log n + k) | O(n log n)| O(n log n)
|
|
332
|
+
* Rank/Percentile | O(log n) | O(n) | O(n log n)
|
|
338
333
|
*/
|
|
339
334
|
@Injectable()
|
|
340
335
|
export class ProductPriceIndexService {
|
|
@@ -348,228 +343,130 @@ export class ProductPriceIndexService {
|
|
|
348
343
|
if (priceCmp !== 0) return priceCmp;
|
|
349
344
|
return a.productId.localeCompare(b.productId);
|
|
350
345
|
},
|
|
346
|
+
enableOrderStatistic: true, // Enables getRank/getByRank/rangeByRank
|
|
351
347
|
});
|
|
352
348
|
this.idToKeyMap = new Map();
|
|
353
349
|
}
|
|
354
350
|
|
|
355
|
-
/**
|
|
351
|
+
/** O(log n) */
|
|
356
352
|
addProduct(product: Product): Product {
|
|
357
353
|
if (this.idToKeyMap.has(product.id))
|
|
358
354
|
throw new BadRequestException(`Product ${product.id} already exists`);
|
|
359
355
|
|
|
360
356
|
product.lastUpdated = new Date();
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
price: product.price,
|
|
364
|
-
productId: product.id,
|
|
365
|
-
};
|
|
366
|
-
|
|
367
|
-
this.priceIndex.add(key, product);
|
|
357
|
+
const key: CompositeKey = { price: product.price, productId: product.id };
|
|
358
|
+
this.priceIndex.set(key, product);
|
|
368
359
|
this.idToKeyMap.set(product.id, key);
|
|
369
|
-
|
|
370
360
|
return product;
|
|
371
361
|
}
|
|
372
362
|
|
|
373
|
-
/**
|
|
374
|
-
updateProduct(productId: string, updates: Partial<Product>): Product {
|
|
375
|
-
const oldKey = this.idToKeyMap.get(productId);
|
|
376
|
-
if (oldKey === undefined)
|
|
377
|
-
throw new NotFoundException(`Product ${productId} not found`);
|
|
378
|
-
|
|
379
|
-
const existing = this.priceIndex.get(oldKey);
|
|
380
|
-
if (!existing)
|
|
381
|
-
throw new NotFoundException(`Product ${productId} not found`);
|
|
382
|
-
|
|
383
|
-
const updated: Product = {
|
|
384
|
-
...existing,
|
|
385
|
-
...updates,
|
|
386
|
-
id: existing.id,
|
|
387
|
-
lastUpdated: new Date(),
|
|
388
|
-
};
|
|
389
|
-
|
|
390
|
-
const newPrice = updates.price ?? existing.price;
|
|
391
|
-
|
|
392
|
-
this.priceIndex.delete(oldKey);
|
|
393
|
-
const currentKey: CompositeKey = {
|
|
394
|
-
price: newPrice,
|
|
395
|
-
productId,
|
|
396
|
-
};
|
|
397
|
-
this.priceIndex.set(currentKey, updated);
|
|
398
|
-
this.idToKeyMap.set(productId, currentKey);
|
|
399
|
-
|
|
400
|
-
return updated;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
/** Time Complexity: O(1) */
|
|
363
|
+
/** O(1) — HashMap lookup */
|
|
404
364
|
getProductById(productId: string): Product {
|
|
405
365
|
const key = this.idToKeyMap.get(productId);
|
|
406
|
-
|
|
407
366
|
if (key === undefined)
|
|
408
367
|
throw new NotFoundException(`Product ${productId} not found`);
|
|
409
|
-
|
|
410
368
|
return this.priceIndex.get(key)!;
|
|
411
369
|
}
|
|
412
370
|
|
|
413
|
-
/**
|
|
371
|
+
/** O(log n + k) — directly returns values, no secondary lookup */
|
|
414
372
|
getProductsByPriceRange(minPrice: number, maxPrice: number): Product[] {
|
|
415
373
|
const range = new Range(
|
|
416
374
|
{ price: minPrice, productId: '' },
|
|
417
375
|
{ price: maxPrice, productId: '\uffff' },
|
|
418
|
-
true,
|
|
419
|
-
true,
|
|
376
|
+
true,
|
|
377
|
+
true,
|
|
420
378
|
);
|
|
421
|
-
|
|
422
|
-
const keys = this.priceIndex.rangeSearch(range, (n) => n.key);
|
|
423
|
-
return keys.map((key) => this.priceIndex.get(key)!);
|
|
379
|
+
return this.priceIndex.rangeSearch(range, (n) => n.value!);
|
|
424
380
|
}
|
|
425
381
|
|
|
426
|
-
/**
|
|
382
|
+
/** O(log n) — NavigableMap floor() */
|
|
427
383
|
getHighestPricedProductWithinBudget(maxBudget: number): Product | null {
|
|
428
|
-
const key: CompositeKey = {
|
|
429
|
-
price: maxBudget,
|
|
430
|
-
productId: '\uffff',
|
|
431
|
-
};
|
|
384
|
+
const key: CompositeKey = { price: maxBudget, productId: '\uffff' };
|
|
432
385
|
const floorKey = this.priceIndex.floor(key);
|
|
433
386
|
return floorKey ? this.priceIndex.get(floorKey)! : null;
|
|
434
387
|
}
|
|
435
388
|
|
|
436
|
-
/**
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
price: minPrice,
|
|
440
|
-
productId: '\uffff',
|
|
441
|
-
};
|
|
442
|
-
const higherKey = this.priceIndex.higher(key);
|
|
443
|
-
return higherKey ? this.priceIndex.get(higherKey)! : null;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/** Time Complexity: O(log n + k) */
|
|
447
|
-
getProductsByTier(tierName: TierName): Product[] {
|
|
448
|
-
const tiers = {
|
|
449
|
-
budget: [0, 50],
|
|
450
|
-
'mid-range': [50, 200],
|
|
451
|
-
premium: [200, Infinity],
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
const [min, max] = tiers[tierName];
|
|
455
|
-
return this.getProductsByPriceRange(min, max);
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
/** Time Complexity: O(log n + k + m) */
|
|
459
|
-
getProductsByPriceAndCategory(
|
|
460
|
-
minPrice: number,
|
|
461
|
-
maxPrice: number,
|
|
462
|
-
category: string,
|
|
463
|
-
): Product[] {
|
|
464
|
-
const priceRangeProducts = this.getProductsByPriceRange(minPrice, maxPrice);
|
|
465
|
-
return priceRangeProducts.filter(
|
|
466
|
-
(p) => p.category.toLowerCase() === category.toLowerCase(),
|
|
467
|
-
);
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
/** Time Complexity: O((log n + k) * log n) */
|
|
471
|
-
applyDiscountToRange(
|
|
472
|
-
minPrice: number,
|
|
473
|
-
maxPrice: number,
|
|
474
|
-
discountPercent: number,
|
|
475
|
-
): Product[] {
|
|
476
|
-
const products = this.getProductsByPriceRange(minPrice, maxPrice);
|
|
477
|
-
const updated: Product[] = [];
|
|
478
|
-
|
|
479
|
-
for (const product of products) {
|
|
480
|
-
const newPrice = product.price * (1 - discountPercent / 100);
|
|
481
|
-
const updatedProduct = this.updateProduct(product.id, {
|
|
482
|
-
price: newPrice,
|
|
483
|
-
});
|
|
484
|
-
updated.push(updatedProduct);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
return updated;
|
|
389
|
+
/** O(n) — iterator protocol, one-liner */
|
|
390
|
+
getAllProductsSortedByPrice(): Product[] {
|
|
391
|
+
return [...this.priceIndex.values()];
|
|
488
392
|
}
|
|
489
393
|
|
|
490
|
-
/**
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
this.priceIndex.delete(key);
|
|
498
|
-
this.idToKeyMap.delete(productId);
|
|
499
|
-
}
|
|
394
|
+
/**
|
|
395
|
+
* O(n) for totalValue, O(log n) for min/max
|
|
396
|
+
* min/max use getLeftMost/getRightMost instead of full traversal
|
|
397
|
+
*/
|
|
398
|
+
getStatistics() {
|
|
399
|
+
if (this.idToKeyMap.size === 0)
|
|
400
|
+
return { totalProducts: 0, priceRange: { min: 0, max: 0 }, averagePrice: 0, totalValue: 0 };
|
|
500
401
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
totalProducts: number;
|
|
504
|
-
priceRange: { min: number; max: number };
|
|
505
|
-
averagePrice: number;
|
|
506
|
-
totalValue: number;
|
|
507
|
-
} {
|
|
508
|
-
if (this.idToKeyMap.size === 0) {
|
|
509
|
-
return {
|
|
510
|
-
totalProducts: 0,
|
|
511
|
-
priceRange: { min: 0, max: 0 },
|
|
512
|
-
averagePrice: 0,
|
|
513
|
-
totalValue: 0,
|
|
514
|
-
};
|
|
515
|
-
}
|
|
402
|
+
const minKey = this.priceIndex.getLeftMost();
|
|
403
|
+
const maxKey = this.priceIndex.getRightMost();
|
|
516
404
|
|
|
517
|
-
let minPrice = Infinity;
|
|
518
|
-
let maxPrice = -Infinity;
|
|
519
405
|
let totalValue = 0;
|
|
520
406
|
let totalProducts = 0;
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
while (entry) {
|
|
525
|
-
const product = this.priceIndex.get(entry.key);
|
|
526
|
-
if (product) {
|
|
527
|
-
minPrice = Math.min(minPrice, product.price);
|
|
528
|
-
maxPrice = Math.max(maxPrice, product.price);
|
|
529
|
-
totalValue += product.price * product.quantity;
|
|
530
|
-
totalProducts += product.quantity;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
entry = this.priceIndex.higher(entry.key, (node) => node);
|
|
407
|
+
for (const [, product] of this.priceIndex) {
|
|
408
|
+
totalValue += product.price * product.quantity;
|
|
409
|
+
totalProducts += product.quantity;
|
|
534
410
|
}
|
|
535
411
|
|
|
536
412
|
return {
|
|
537
|
-
totalProducts
|
|
538
|
-
priceRange: { min:
|
|
413
|
+
totalProducts,
|
|
414
|
+
priceRange: { min: minKey?.price ?? 0, max: maxKey?.price ?? 0 },
|
|
539
415
|
averagePrice: totalValue / totalProducts,
|
|
540
416
|
totalValue,
|
|
541
417
|
};
|
|
542
418
|
}
|
|
543
419
|
|
|
544
|
-
|
|
545
|
-
getAllProductsSortedByPrice(): Product[] {
|
|
546
|
-
const products: Product[] = [];
|
|
547
|
-
let curNode = this.priceIndex.getLeftMost((node) => node);
|
|
420
|
+
// ── Order-Statistic API (rank-based queries) ──────────────────────
|
|
548
421
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
422
|
+
/** O(log n + pageSize) — rank-based pagination */
|
|
423
|
+
getProductsByPage(page: number, pageSize: number): Product[] {
|
|
424
|
+
const start = page * pageSize;
|
|
425
|
+
const end = Math.min(start + pageSize - 1, this.priceIndex.size - 1);
|
|
426
|
+
if (start >= this.priceIndex.size) return [];
|
|
427
|
+
const keys = this.priceIndex.rangeByRank(start, end);
|
|
428
|
+
return keys.map((key) => this.priceIndex.get(key)!);
|
|
429
|
+
}
|
|
553
430
|
|
|
554
|
-
|
|
431
|
+
/** O(log n) — what % of products are cheaper */
|
|
432
|
+
getPricePercentile(productId: string): number {
|
|
433
|
+
const key = this.idToKeyMap.get(productId);
|
|
434
|
+
if (!key) throw new NotFoundException(`Product ${productId} not found`);
|
|
435
|
+
return (this.priceIndex.getRank(key) / this.priceIndex.size) * 100;
|
|
555
436
|
}
|
|
556
437
|
|
|
557
|
-
/** O(
|
|
558
|
-
|
|
559
|
-
|
|
438
|
+
/** O(log n) — median product */
|
|
439
|
+
getMedianProduct(): Product | null {
|
|
440
|
+
if (this.priceIndex.size === 0) return null;
|
|
441
|
+
const key = this.priceIndex.getByRank(Math.floor((this.priceIndex.size - 1) / 2));
|
|
442
|
+
return key ? this.priceIndex.get(key)! : null;
|
|
560
443
|
}
|
|
561
444
|
|
|
562
|
-
/** O(
|
|
563
|
-
|
|
564
|
-
|
|
445
|
+
/** O(log n + k) — top N cheapest */
|
|
446
|
+
getTopNCheapest(n: number): Product[] {
|
|
447
|
+
const end = Math.min(n - 1, this.priceIndex.size - 1);
|
|
448
|
+
if (end < 0) return [];
|
|
449
|
+
return this.priceIndex.rangeByRank(0, end).map((key) => this.priceIndex.get(key)!);
|
|
565
450
|
}
|
|
566
451
|
|
|
567
|
-
/** O(n) */
|
|
568
|
-
|
|
569
|
-
|
|
452
|
+
/** O(log n + k) — top N most expensive */
|
|
453
|
+
getTopNExpensive(n: number): Product[] {
|
|
454
|
+
const size = this.priceIndex.size;
|
|
455
|
+
if (size === 0) return [];
|
|
456
|
+
const start = Math.max(size - n, 0);
|
|
457
|
+
return this.priceIndex.rangeByRank(start, size - 1)
|
|
458
|
+
.map((key) => this.priceIndex.get(key)!)
|
|
459
|
+
.reverse();
|
|
570
460
|
}
|
|
571
|
-
}
|
|
572
461
|
|
|
462
|
+
/** O(log n) — dynamic tier by percentile, no hardcoded price ranges */
|
|
463
|
+
getTierByPercentile(productId: string): TierName {
|
|
464
|
+
const pct = this.getPricePercentile(productId);
|
|
465
|
+
if (pct < 33) return 'budget';
|
|
466
|
+
if (pct < 66) return 'mid-range';
|
|
467
|
+
return 'premium';
|
|
468
|
+
}
|
|
469
|
+
}
|
|
573
470
|
```
|
|
574
471
|
|
|
575
472
|
### Use Case: Task Queue Controller
|
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
sidebar_label: "OVERVIEW"
|
|
3
3
|
description: "Complete overview of all 20+ data structures: trees, heaps, graphs, queues, linked lists, hash maps, and more."
|
|
4
4
|
title: "Data Structures Overview — Trees, Heaps, Graphs, Queues"
|
|
5
|
-
keywords: [typescript data structures overview, red black tree, heap, priority queue, trie, graph, deque, treemap, treeset]
|
|
5
|
+
keywords: ["typescript data structures overview", "red black tree", "heap", "priority queue", "trie", "graph", "deque", "treemap", "treeset"]
|
|
6
6
|
---
|
|
7
|
-
|
|
8
7
|
# OVERVIEW
|
|
9
8
|
|
|
10
9
|
A quick-reference guide to all structures, common operations, and usage patterns. For complete API details with method signatures and examples, see the **[Full API Docs](https://data-structure-typed-docs.vercel.app/)**.
|
|
11
10
|
|
|
12
|
-
**[Back to README](
|
|
11
|
+
**[Back to README](/docs/guide/quick-start) • [API Docs](https://data-structure-typed-docs.vercel.app/) • [Real-World Examples](/guide/guides.md) • [Performance](/guide/performance.md)**
|
|
13
12
|
|
|
14
13
|
---
|
|
15
14
|
|
|
@@ -57,7 +56,7 @@ A quick-reference guide to all structures, common operations, and usage patterns
|
|
|
57
56
|
import { Stack } from 'data-structure-typed';
|
|
58
57
|
|
|
59
58
|
const stack = new Stack<number>([1, 2]);
|
|
60
|
-
stack.push(3); // add to
|
|
59
|
+
stack.push(3); // add to top
|
|
61
60
|
const top = stack.pop(); // Remove from top - O(1)
|
|
62
61
|
const peek = stack.peek(); // View top
|
|
63
62
|
stack.print(); // [1, 2]
|
|
@@ -149,11 +148,6 @@ rbTree.print()
|
|
|
149
148
|
// / \
|
|
150
149
|
// 1 4
|
|
151
150
|
|
|
152
|
-
// Order-Statistic mode — O(log n) rank queries
|
|
153
|
-
const ost = new RedBlackTree<number, string>([[1, 'A'], [2, 'B'], [3, 'C']], { enableOrderStatistic: true });
|
|
154
|
-
ost.getByRank(0); // 1 (smallest key)
|
|
155
|
-
ost.getRank(2); // 1 (one element before key 2)
|
|
156
|
-
ost.rangeByRank(0, 1); // [1, 2] (first two elements)
|
|
157
151
|
```
|
|
158
152
|
|
|
159
153
|
#### AVL Tree
|
|
@@ -173,6 +167,97 @@ avl.print()
|
|
|
173
167
|
// 4 9
|
|
174
168
|
```
|
|
175
169
|
|
|
170
|
+
#### TreeMap (Ordered Map)
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import { TreeMap } from 'data-structure-typed';
|
|
174
|
+
|
|
175
|
+
const tm = new TreeMap<number, string>([[3, 'c'], [1, 'a'], [2, 'b']]);
|
|
176
|
+
tm.set(4, 'd'); // Set key-value - O(log n)
|
|
177
|
+
tm.get(2); // 'b' - O(log n)
|
|
178
|
+
tm.has(3); // true
|
|
179
|
+
tm.delete(1); // Remove - O(log n)
|
|
180
|
+
|
|
181
|
+
// Navigation — Java NavigableMap-style
|
|
182
|
+
tm.first(); // [2, 'b'] — smallest entry
|
|
183
|
+
tm.last(); // [4, 'd'] — largest entry
|
|
184
|
+
tm.ceiling(3); // [3, 'c'] — smallest >= 3
|
|
185
|
+
tm.floor(2); // [2, 'b'] — largest <= 2
|
|
186
|
+
tm.higher(2); // [3, 'c'] — strictly > 2
|
|
187
|
+
tm.lower(3); // [2, 'b'] — strictly < 3
|
|
188
|
+
|
|
189
|
+
// Iteration (sorted order)
|
|
190
|
+
console.log([...tm.keys()]); // [2, 3, 4]
|
|
191
|
+
console.log([...tm.values()]); // ['b', 'c', 'd']
|
|
192
|
+
|
|
193
|
+
// Bulk operations
|
|
194
|
+
tm.setMany([[5, 'e'], [6, 'f']]); // Set multiple at once
|
|
195
|
+
|
|
196
|
+
// Functional
|
|
197
|
+
const filtered = tm.filter((v, k) => k > 2);
|
|
198
|
+
const mapped = tm.map((v, k) => [k * 10, v!.toUpperCase()] as [number, string]);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### TreeSet (Ordered Set)
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
import { TreeSet } from 'data-structure-typed';
|
|
205
|
+
|
|
206
|
+
const ts = new TreeSet<number>([5, 3, 8, 1]);
|
|
207
|
+
ts.add(4); // Add - O(log n)
|
|
208
|
+
ts.has(3); // true
|
|
209
|
+
ts.delete(5); // Remove - O(log n)
|
|
210
|
+
|
|
211
|
+
// Navigation
|
|
212
|
+
ts.first(); // 1
|
|
213
|
+
ts.last(); // 8
|
|
214
|
+
ts.ceiling(4); // 4 — smallest >= 4
|
|
215
|
+
ts.floor(6); // 4 — largest <= 6
|
|
216
|
+
ts.higher(3); // 4 — strictly > 3
|
|
217
|
+
ts.lower(4); // 3 — strictly < 4
|
|
218
|
+
|
|
219
|
+
// Iteration (sorted order)
|
|
220
|
+
console.log([...ts.keys()]); // [1, 3, 4, 8]
|
|
221
|
+
|
|
222
|
+
// Bulk operations
|
|
223
|
+
ts.addMany([10, 20, 30]); // Add multiple at once
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
#### Order-Statistic Tree (Rank Queries)
|
|
227
|
+
|
|
228
|
+
Enable `enableOrderStatistic: true` on any tree-based structure to get O(log n) rank operations:
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import { RedBlackTree, TreeMap, TreeSet } from 'data-structure-typed';
|
|
232
|
+
|
|
233
|
+
// Works with RedBlackTree, TreeMap, TreeSet, TreeMultiMap, TreeMultiSet
|
|
234
|
+
const tree = new RedBlackTree<number, string>(
|
|
235
|
+
[[100, 'Alice'], [85, 'Bob'], [92, 'Charlie'], [78, 'Diana']],
|
|
236
|
+
{ comparator: (a, b) => b - a, enableOrderStatistic: true }
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
// getByRank(k) — element at position k in tree order, O(log n)
|
|
240
|
+
tree.getByRank(0); // 100 (1st in tree order)
|
|
241
|
+
tree.getByRank(2); // 92 (3rd in tree order)
|
|
242
|
+
|
|
243
|
+
// getRank(key) — count of elements before key in tree order, O(log n)
|
|
244
|
+
tree.getRank(92); // 2
|
|
245
|
+
|
|
246
|
+
// rangeByRank(start, end) — elements between positions, O(log n + k)
|
|
247
|
+
tree.rangeByRank(0, 2); // [100, 92, 85] — positions 0..2
|
|
248
|
+
|
|
249
|
+
// Also works with wrapper classes
|
|
250
|
+
const tm = new TreeMap<number, string>([], { enableOrderStatistic: true });
|
|
251
|
+
tm.set(10, 'a'); tm.set(20, 'b'); tm.set(30, 'c');
|
|
252
|
+
tm.getByRank(1); // [20, 'b']
|
|
253
|
+
tm.getRank(20); // 1
|
|
254
|
+
|
|
255
|
+
const ts = new TreeSet<number>([], { enableOrderStatistic: true });
|
|
256
|
+
ts.addMany([10, 20, 30]);
|
|
257
|
+
ts.getByRank(0); // 10
|
|
258
|
+
ts.getRank(30); // 2
|
|
259
|
+
```
|
|
260
|
+
|
|
176
261
|
### Heap & Priority Queue
|
|
177
262
|
|
|
178
263
|
#### Heap
|
|
@@ -191,7 +276,9 @@ const peek = minHeap.peek(); // View minimum - O(1)
|
|
|
191
276
|
```typescript
|
|
192
277
|
import { MaxPriorityQueue } from 'data-structure-typed';
|
|
193
278
|
|
|
194
|
-
const pq = new MaxPriorityQueue<Task>(
|
|
279
|
+
const pq = new MaxPriorityQueue<Task>([], {
|
|
280
|
+
comparator: (a, b) => b.priority - a.priority
|
|
281
|
+
});
|
|
195
282
|
pq.add({ id: 1, priority: 5 }); // Add - O(log n)
|
|
196
283
|
const task = pq.poll(); // Remove highest - O(log n)
|
|
197
284
|
const size = pq.size; // Current size
|
|
@@ -273,7 +360,7 @@ heap.peek(); // Highest priority element
|
|
|
273
360
|
heap.size; // Current size
|
|
274
361
|
|
|
275
362
|
// Trie
|
|
276
|
-
trie.
|
|
363
|
+
trie.has('hello'); // true
|
|
277
364
|
trie.hasPrefix('hel'); // true
|
|
278
365
|
|
|
279
366
|
// Graph
|
|
@@ -303,6 +390,12 @@ graph.deleteVertex('A'); // Remove vertex
|
|
|
303
390
|
// All structures support:
|
|
304
391
|
structure.clear(); // Remove all elements
|
|
305
392
|
structure.delete(key); // Remove specific
|
|
393
|
+
|
|
394
|
+
// Conditional delete (BST-family and Deque)
|
|
395
|
+
tree.deleteWhere(node => node.key < 10); // Delete all matching
|
|
396
|
+
tree.deleteWhere(node => node.key < 10, true); // Delete first match only
|
|
397
|
+
tree.deleteWhere(new Range(5, 15)); // Delete by range
|
|
398
|
+
deque.deleteWhere((val, idx) => val > 100); // Deque predicate delete
|
|
306
399
|
```
|
|
307
400
|
|
|
308
401
|
---
|
|
@@ -335,12 +428,33 @@ structure.size; // Element count
|
|
|
335
428
|
structure.isEmpty(); // Check empty
|
|
336
429
|
```
|
|
337
430
|
|
|
431
|
+
### Raw Data Mapping
|
|
432
|
+
|
|
433
|
+
Pass raw objects directly — no `.map()` pre-processing needed:
|
|
434
|
+
|
|
435
|
+
```typescript
|
|
436
|
+
// toElementFn — extract a field, store only that (Heap, Queue, Stack, LinkedList, Trie)
|
|
437
|
+
const heap = new MinHeap<number, User>(users, {
|
|
438
|
+
toElementFn: u => u.age
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// toEntryFn — split into key-value pairs (TreeMap, HashMap, SkipList)
|
|
442
|
+
const map = new TreeMap<number, User, User>(users, {
|
|
443
|
+
toEntryFn: u => [u.id, u]
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
// comparator — store full objects, sort by a field (all sorted structures)
|
|
447
|
+
const set = new TreeSet<User>(users, {
|
|
448
|
+
comparator: (a, b) => a.id - b.id
|
|
449
|
+
});
|
|
450
|
+
```
|
|
451
|
+
|
|
338
452
|
### Structure-Specific Methods
|
|
339
453
|
|
|
340
454
|
#### Trees
|
|
341
455
|
|
|
342
456
|
```typescript
|
|
343
|
-
tree.height; // Tree height
|
|
457
|
+
tree.height; // Tree height (getter)
|
|
344
458
|
tree.isAVLBalanced(); // Balance check
|
|
345
459
|
tree.getNode(key); // Get node object
|
|
346
460
|
tree.getHeight(key); // Node height
|
|
@@ -351,10 +465,10 @@ tree.getRightMost(); // Rightmost node
|
|
|
351
465
|
#### Deque
|
|
352
466
|
|
|
353
467
|
```typescript
|
|
354
|
-
deque.
|
|
355
|
-
deque.
|
|
356
|
-
deque.
|
|
357
|
-
deque.
|
|
468
|
+
deque.first; // View front (getter)
|
|
469
|
+
deque.last; // View back (getter)
|
|
470
|
+
deque.shift(); // Remove front - O(1)
|
|
471
|
+
deque.pop(); // Remove back - O(1)
|
|
358
472
|
```
|
|
359
473
|
|
|
360
474
|
#### Graph
|
|
@@ -470,7 +584,7 @@ const sorted = [...new RedBlackTree(data).keys()]; // Instant sort!
|
|
|
470
584
|
|
|
471
585
|
---
|
|
472
586
|
|
|
473
|
-
## SkipList
|
|
587
|
+
## SkipList
|
|
474
588
|
|
|
475
589
|
Probabilistic sorted containers. Interchangeable with `TreeMap`/`TreeSet`.
|
|
476
590
|
|
|
@@ -42,6 +42,10 @@ const features = [
|
|
|
42
42
|
title: '📦 Zero Dependencies',
|
|
43
43
|
description: 'Pure TypeScript. No runtime dependencies. Tree-shakeable with subpath exports — bundle only what you use.',
|
|
44
44
|
},
|
|
45
|
+
{
|
|
46
|
+
title: '🔄 Raw Data In, Structure Out',
|
|
47
|
+
description: 'Pass raw objects directly with toEntryFn, toElementFn, or comparator. No .map() pre-processing needed — unique to this library in JS/TS.',
|
|
48
|
+
},
|
|
45
49
|
{
|
|
46
50
|
title: '✅ Battle-Tested',
|
|
47
51
|
description: '2600+ tests, 99%+ coverage. CLRS-correct Red-Black Tree, ACL-style Segment Tree. Production-ready.',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "data-structure-typed",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.3",
|
|
4
4
|
"description": "Production-ready TypeScript data structures: Heap, Deque, Trie, Graph, Red-Black Tree, TreeMap, TreeSet, and more. Zero dependencies, type-safe, with getRank/getByRank/rangeByRank support.",
|
|
5
5
|
"browser": "dist/umd/data-structure-typed.min.js",
|
|
6
6
|
"umd:main": "dist/umd/data-structure-typed.min.js",
|
|
@@ -154,6 +154,7 @@
|
|
|
154
154
|
"format:test": "prettier --write 'test/**/*.{js,ts}'",
|
|
155
155
|
"inspect": "npm run build && npm run check && npm run lint",
|
|
156
156
|
"ci": "env && git fetch --tags && npm run update:subs && npm run inspect && npm run test:coverage && npm run changelog",
|
|
157
|
+
"docs:sync": "node scripts/sync-docs-to-site.mjs",
|
|
157
158
|
"docs:api": "npm run gen:examples && npm run build:typedoc-plugin && cd docs-site-docusaurus && npx typedoc --options typedoc.json && node sort-protected.mjs",
|
|
158
159
|
"docs:dev": "cd docs-site-docusaurus && npm run start",
|
|
159
160
|
"docs:build": "cd docs-site-docusaurus && rm -rf docs/api && npx typedoc --options typedoc.json && node sort-protected.mjs && npm run build",
|
|
@@ -193,11 +194,11 @@
|
|
|
193
194
|
"@typescript-eslint/eslint-plugin": "^8.12.1",
|
|
194
195
|
"@typescript-eslint/parser": "^8.12.1",
|
|
195
196
|
"auto-changelog": "^2.5.0",
|
|
196
|
-
"avl-tree-typed": "^2.5.
|
|
197
|
+
"avl-tree-typed": "^2.5.2",
|
|
197
198
|
"benchmark": "^2.1.4",
|
|
198
|
-
"binary-tree-typed": "^2.5.
|
|
199
|
-
"bst-typed": "^2.5.
|
|
200
|
-
"data-structure-typed": "^2.5.
|
|
199
|
+
"binary-tree-typed": "^2.5.2",
|
|
200
|
+
"bst-typed": "^2.5.2",
|
|
201
|
+
"data-structure-typed": "^2.5.2",
|
|
201
202
|
"dependency-cruiser": "^16.5.0",
|
|
202
203
|
"doctoc": "^2.2.1",
|
|
203
204
|
"eslint": "^9.13.0",
|
|
@@ -206,7 +207,7 @@
|
|
|
206
207
|
"eslint-import-resolver-typescript": "^3.6.3",
|
|
207
208
|
"eslint-plugin-import": "^2.31.0",
|
|
208
209
|
"fast-glob": "^3.3.2",
|
|
209
|
-
"heap-typed": "^2.5.
|
|
210
|
+
"heap-typed": "^2.5.2",
|
|
210
211
|
"istanbul-badges-readme": "^1.9.0",
|
|
211
212
|
"jest": "^29.7.0",
|
|
212
213
|
"js-sdsl": "^4.4.2",
|